diff --git a/lib/food_entry_bloc.dart b/lib/food_entry_bloc.dart index fee871f..ffc4741 100644 --- a/lib/food_entry_bloc.dart +++ b/lib/food_entry_bloc.dart @@ -4,7 +4,7 @@ import 'package:uuid/uuid.dart'; class FoodEntryBloc extends Bloc { final FoodEntryState initialState; - final FoodStorage storage; + final AppStorage storage; final DateTime forDate; FoodEntryBloc( diff --git a/lib/main.dart b/lib/main.dart index cc245bb..c122e5e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:calodiary/theme_bloc.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; @@ -9,34 +10,64 @@ import 'package:calodiary/storage/storage.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - var storage = await FoodStorage.create(); + var storage = await AppStorage.create(); var kcalLimit = await storage.readLimit(); + var brightness = await storage.readBrightness(); - runApp(MainApp(storage: storage, kcalLimit: kcalLimit)); + runApp( + MainApp( + storage: storage, + kcalLimit: kcalLimit, + brightness: brightness, + ), + ); } class MainApp extends StatelessWidget { - final FoodStorage storage; + final AppStorage storage; final double kcalLimit; + final String brightness; - const MainApp({required this.storage, required this.kcalLimit, super.key}); + const MainApp( + {required this.storage, + required this.kcalLimit, + required this.brightness, + super.key}); @override Widget build(BuildContext context) { - return BlocProvider( - create: (context) => SettingsDataBloc(SettingsState(kcalLimit: kcalLimit), - storage: storage), - child: MaterialApp.router( - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: const [ - Locale('de'), - ], - theme: ThemeData.dark(), - routerConfig: router, + return MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => SettingsDataBloc( + SettingsState(kcalLimit: kcalLimit), + storage: storage), + ), + BlocProvider( + create: (context) => ThemeDataBloc(ThemeState(brightness: brightness), + storage: storage), + ), + ], + child: BlocBuilder( + builder: (context, state) { + var switchToTheme = ThemeData.light(); + if (state.brightness == 'dark') { + switchToTheme = ThemeData.dark(); + } + + return MaterialApp.router( + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: const [ + Locale('de'), + ], + theme: switchToTheme, + routerConfig: router, + ); + }, ), ); } diff --git a/lib/perdate_widget.dart b/lib/perdate_widget.dart index 56a83dc..a1d2ea2 100644 --- a/lib/perdate_widget.dart +++ b/lib/perdate_widget.dart @@ -1,3 +1,4 @@ +import 'package:calodiary/theme_bloc.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; @@ -18,7 +19,7 @@ class PerDateWidget extends StatefulWidget { } class _PerDateWidgetState extends State { - late FoodStorage storage; + late AppStorage storage; late Future> entriesFuture; late List entries; @@ -26,7 +27,7 @@ class _PerDateWidgetState extends State { void initState() { super.initState(); - storage = FoodStorage.getInstance(); + storage = AppStorage.getInstance(); entriesFuture = storage.getEntriesForDate(widget.date); entriesFuture.then((val) { entries = val; @@ -39,6 +40,14 @@ class _PerDateWidgetState extends State { return Scaffold( appBar: AppBar( title: Text(formattedDate), + actions: [ + IconButton( + icon: const Icon(Icons.lightbulb), + onPressed: () { + context.read().add(ThemeToggleEvent()); + }, + ), + ], ), drawer: const AppDrawer(), body: FutureBuilder( diff --git a/lib/settings_bloc.dart b/lib/settings_bloc.dart index ac88d5c..6c76f04 100644 --- a/lib/settings_bloc.dart +++ b/lib/settings_bloc.dart @@ -2,7 +2,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:calodiary/storage/storage.dart'; class SettingsDataBloc extends Bloc { - final FoodStorage storage; + final AppStorage storage; SettingsDataBloc(super.initialState, {required this.storage}) { on(persistDailyLimit); diff --git a/lib/storage/storage.dart b/lib/storage/storage.dart index f6a9096..688897f 100644 --- a/lib/storage/storage.dart +++ b/lib/storage/storage.dart @@ -2,22 +2,31 @@ import 'dart:io'; import 'package:calodiary/food_entry_bloc.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:universal_platform/universal_platform.dart'; -class FoodStorage { - static late FoodStorage _instance; +class AppStorage { + static late AppStorage _instance; late String path; - FoodStorage._create(); + AppStorage._create(); - static Future create() async { - var storage = FoodStorage._create(); - var directory = await getApplicationCacheDirectory(); - storage.path = directory.path; + static Future create() async { + var storage = AppStorage._create(); + + Directory dir = Directory(''); + + if (UniversalPlatform.isDesktop) { + dir = await getApplicationCacheDirectory(); + } else if (UniversalPlatform.isAndroid) { + dir = await getApplicationDocumentsDirectory(); + } + + storage.path = dir.path; _instance = storage; return _instance; } - static FoodStorage getInstance() => _instance; + static AppStorage getInstance() => _instance; Future> getEntriesForDate(DateTime date) async { List entries = []; @@ -93,4 +102,34 @@ class FoodStorage { return limit; } + + Future readBrightness() async { + var filePath = '$path/brightness'; + var file = File(filePath); + var exists = await file.exists(); + + if (!exists) { + return 'dark'; + } + + var line = await file.readAsLines(); + + if (line.isEmpty || (line[0] != 'dark' && line[0] != 'light')) { + return 'dark'; + } + + return line[0]; + } + + Future writeBrightness(String brightness) async { + var filePath = '$path/brightness'; + var file = File(filePath); + var exists = await file.exists(); + + if (!exists) { + file.create(); + } + + await file.writeAsString(brightness); + } } diff --git a/lib/theme_bloc.dart b/lib/theme_bloc.dart new file mode 100644 index 0000000..6981490 --- /dev/null +++ b/lib/theme_bloc.dart @@ -0,0 +1,37 @@ +import 'package:calodiary/storage/storage.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class ThemeDataBloc extends Bloc { + final AppStorage storage; + + ThemeDataBloc(super.initialState, {required this.storage}) { + on(switchTheme); + } + + void switchTheme(ThemeToggleEvent event, Emitter emit) async { + String newBrightness = 'light'; + if (state.brightness == 'light') newBrightness = 'dark'; + + persistTheme(newBrightness); + + emit(ThemeState(brightness: newBrightness)); + } + + void persistTheme(String brightness) async { + storage.writeBrightness(brightness); + } + + Future getPersistedTheme() async { + return storage.readBrightness(); + } +} + +class ThemeToggleEvent { + ThemeToggleEvent(); +} + +class ThemeState { + final String brightness; + + ThemeState({required this.brightness}); +} diff --git a/pubspec.lock b/pubspec.lock index 7bd45e2..8c4589d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -442,6 +442,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + universal_platform: + dependency: "direct main" + description: + name: universal_platform + sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec" + url: "https://pub.dev" + source: hosted + version: "1.1.0" uuid: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 323e73a..2f544d1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: path_provider: ^2.1.3 quiver: ^3.2.1 settings_ui: ^2.0.2 + universal_platform: ^1.1.0 uuid: ^4.4.0 dev_dependencies: