import 'dart:typed_data'; import 'package:dadtuber/date_utils.dart'; import 'package:dadtuber/index_file.dart'; import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'DadTuber', theme: ThemeData( // This is the theme of your application. // // TRY THIS: Try running your application with "flutter run". You'll see // the application has a purple toolbar. Then, without quitting the app, // try changing the seedColor in the colorScheme below to Colors.green // and then invoke "hot reload" (save your changes or press the "hot // reload" button in a Flutter-supported IDE, or press "r" if you used // the command line to start the app). // // Notice that the counter didn't reset back to zero; the application // state is not lost during the reload. To reset the state, use hot // restart instead. // // This works for code too, not just values: Most code changes can be // tested with just a hot reload. colorScheme: ColorScheme.fromSeed(seedColor: Colors.red), useMaterial3: true, elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom(minimumSize: Size.fromRadius(24)), ), ), home: const MyHomePage(title: 'DadTuber'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect // how it looks. // This class is the configuration for the state. It holds the values (in this // case the title) provided by the parent (in this case the App widget) and // used by the build method of the State. Fields in a Widget subclass are // always marked "final". final String title; @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { late Future _projectIndexBuilder; @override void initState() { super.initState(); builder() async { final dir = await getApplicationDocumentsDirectory(); final path = "${dir.path}/index"; try { return ProjectIndex.load(path); } catch (_) { return ProjectIndex.blank(); } } _projectIndexBuilder = builder(); } @override Widget build(BuildContext context) { // This method is rerun every time setState is called, for instance as done // by the _incrementCounter method above. // // The Flutter framework has been optimized to make rerunning build methods // fast, so that you can just rebuild anything that needs updating rather // than having to individually change instances of widgets. return Scaffold( appBar: AppBar( // TRY THIS: Try changing the color here to a specific color (to // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar // change color while the other colors stay the same. backgroundColor: Theme.of(context).colorScheme.inversePrimary, // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. title: Text(widget.title), ), body: FocusTraversalGroup( policy: WidgetOrderTraversalPolicy(), child: OrientationBuilder( builder: (context, orientation) => orientation == Orientation.landscape ? Container( padding: EdgeInsets.all(24), child: Row( spacing: 48, children: [ CreateNewColumn(showHeader: true), Expanded( child: SavedProjectsColumn( projectIndexBuilder: _projectIndexBuilder, showHeader: true, ), ), ], ), ) : Column( spacing: 16, children: [ CreateNewColumn(showHeader: false), Expanded( child: SavedProjectsColumn( projectIndexBuilder: _projectIndexBuilder, showHeader: false, ), ), ], ), ), ), ); } } class CreateNewColumn extends StatelessWidget { final bool showHeader; const CreateNewColumn({required this.showHeader, super.key}); @override Widget build(BuildContext context) { return Column( spacing: 12, children: [ showHeader ? Text( "Create New", style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ) : SizedBox(), ElevatedButton.icon( icon: Icon(Icons.video_file), onPressed: () => (), label: Text('Create a new video'), ), ElevatedButton.icon( icon: Icon(Icons.image), onPressed: () => (), label: Text('Create a new image'), ), ElevatedButton.icon( icon: Icon(Icons.audio_file), onPressed: () => (), label: Text('Create a new sound'), ), ], ); } } class SavedProjectsColumn extends StatelessWidget { final bool showHeader; final Future projectIndexBuilder; const SavedProjectsColumn({ required this.projectIndexBuilder, required this.showHeader, super.key, }); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.symmetric(horizontal: 12), child: Text( "Saved Projects", style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ), ), Expanded( child: FutureBuilder( future: projectIndexBuilder, builder: (cx, snapshot) { if (snapshot.hasData) { return SavedProjectsListView(snapshot.data!); } else if (snapshot.hasError) { return Center(child: Text("An error occurred")); } else { return Center(child: CircularProgressIndicator()); } }, ), ), ], ); } } class SavedProjectsListView extends StatelessWidget { final ProjectIndex _projectIndex; const SavedProjectsListView(this._projectIndex, {super.key}); @override Widget build(BuildContext context) { return ListView.builder( addAutomaticKeepAlives: false, itemCount: _projectIndex.projects.length, itemBuilder: (cx, idx) { final project = _projectIndex.projects[idx]; return SavedProjectTile( title: project.title, image: _projectIndex.getImage(project.title), lastModified: project.lastModified, projectType: project.type, ); }, ); } } class SavedProjectTile extends StatelessWidget { final String title; final Uint8List? image; final DateTime lastModified; final ProjectType projectType; const SavedProjectTile({ required this.title, this.image, required this.lastModified, required this.projectType, super.key, }); @override Widget build(BuildContext context) { return ListTile( leading: SavedProjectThumbnail(projectType: projectType, image: image), title: Text( title, overflow: TextOverflow.ellipsis, ), subtitle: Text('Edited ${daysAgo(lastModified)}'), trailing: Text(projectType.normalString()), onTap: () => (), ); } } class SavedProjectThumbnail extends StatelessWidget { final ProjectType projectType; final Uint8List? image; const SavedProjectThumbnail({ required this.projectType, required this.image, super.key, }); @override Widget build(BuildContext context) { return SizedBox( width: 96, height: 54, child: Stack( children: [ image != null ? Image.memory(image!, width: 80, height: 45) : SizedBox(width: 80, height: 45), Center( child: Opacity(opacity: 0.5, child: Icon(projectType.icon())), ), ], ), ); } }