Introduce themebloc and persist theme

This commit is contained in:
Marco 2024-06-12 14:42:29 +02:00
parent 000bd9a413
commit 8e1cf835e4
8 changed files with 155 additions and 30 deletions

View File

@ -4,7 +4,7 @@ import 'package:uuid/uuid.dart';
class FoodEntryBloc extends Bloc<FoodEvent, FoodEntryState> { class FoodEntryBloc extends Bloc<FoodEvent, FoodEntryState> {
final FoodEntryState initialState; final FoodEntryState initialState;
final FoodStorage storage; final AppStorage storage;
final DateTime forDate; final DateTime forDate;
FoodEntryBloc( FoodEntryBloc(

View File

@ -1,3 +1,4 @@
import 'package:calodiary/theme_bloc.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
@ -9,34 +10,64 @@ import 'package:calodiary/storage/storage.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
var storage = await FoodStorage.create(); var storage = await AppStorage.create();
var kcalLimit = await storage.readLimit(); 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 { class MainApp extends StatelessWidget {
final FoodStorage storage; final AppStorage storage;
final double kcalLimit; 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return MultiBlocProvider(
create: (context) => SettingsDataBloc(SettingsState(kcalLimit: kcalLimit), providers: [
storage: storage), BlocProvider(
child: MaterialApp.router( create: (context) => SettingsDataBloc(
localizationsDelegates: const [ SettingsState(kcalLimit: kcalLimit),
GlobalMaterialLocalizations.delegate, storage: storage),
GlobalWidgetsLocalizations.delegate, ),
GlobalCupertinoLocalizations.delegate, BlocProvider(
], create: (context) => ThemeDataBloc(ThemeState(brightness: brightness),
supportedLocales: const [ storage: storage),
Locale('de'), ),
], ],
theme: ThemeData.dark(), child: BlocBuilder<ThemeDataBloc, ThemeState>(
routerConfig: router, 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,
);
},
), ),
); );
} }

View File

@ -1,3 +1,4 @@
import 'package:calodiary/theme_bloc.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
@ -18,7 +19,7 @@ class PerDateWidget extends StatefulWidget {
} }
class _PerDateWidgetState extends State<PerDateWidget> { class _PerDateWidgetState extends State<PerDateWidget> {
late FoodStorage storage; late AppStorage storage;
late Future<List<FoodEntry>> entriesFuture; late Future<List<FoodEntry>> entriesFuture;
late List<FoodEntry> entries; late List<FoodEntry> entries;
@ -26,7 +27,7 @@ class _PerDateWidgetState extends State<PerDateWidget> {
void initState() { void initState() {
super.initState(); super.initState();
storage = FoodStorage.getInstance(); storage = AppStorage.getInstance();
entriesFuture = storage.getEntriesForDate(widget.date); entriesFuture = storage.getEntriesForDate(widget.date);
entriesFuture.then((val) { entriesFuture.then((val) {
entries = val; entries = val;
@ -39,6 +40,14 @@ class _PerDateWidgetState extends State<PerDateWidget> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(formattedDate), title: Text(formattedDate),
actions: [
IconButton(
icon: const Icon(Icons.lightbulb),
onPressed: () {
context.read<ThemeDataBloc>().add(ThemeToggleEvent());
},
),
],
), ),
drawer: const AppDrawer(), drawer: const AppDrawer(),
body: FutureBuilder( body: FutureBuilder(

View File

@ -2,7 +2,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:calodiary/storage/storage.dart'; import 'package:calodiary/storage/storage.dart';
class SettingsDataBloc extends Bloc<SettingsEvent, SettingsState> { class SettingsDataBloc extends Bloc<SettingsEvent, SettingsState> {
final FoodStorage storage; final AppStorage storage;
SettingsDataBloc(super.initialState, {required this.storage}) { SettingsDataBloc(super.initialState, {required this.storage}) {
on<DailyKcalLimitUpdated>(persistDailyLimit); on<DailyKcalLimitUpdated>(persistDailyLimit);

View File

@ -2,22 +2,31 @@ import 'dart:io';
import 'package:calodiary/food_entry_bloc.dart'; import 'package:calodiary/food_entry_bloc.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:universal_platform/universal_platform.dart';
class FoodStorage { class AppStorage {
static late FoodStorage _instance; static late AppStorage _instance;
late String path; late String path;
FoodStorage._create(); AppStorage._create();
static Future<FoodStorage> create() async { static Future<AppStorage> create() async {
var storage = FoodStorage._create(); var storage = AppStorage._create();
var directory = await getApplicationCacheDirectory();
storage.path = directory.path; Directory dir = Directory('');
if (UniversalPlatform.isDesktop) {
dir = await getApplicationCacheDirectory();
} else if (UniversalPlatform.isAndroid) {
dir = await getApplicationDocumentsDirectory();
}
storage.path = dir.path;
_instance = storage; _instance = storage;
return _instance; return _instance;
} }
static FoodStorage getInstance() => _instance; static AppStorage getInstance() => _instance;
Future<List<FoodEntry>> getEntriesForDate(DateTime date) async { Future<List<FoodEntry>> getEntriesForDate(DateTime date) async {
List<FoodEntry> entries = []; List<FoodEntry> entries = [];
@ -93,4 +102,34 @@ class FoodStorage {
return limit; return limit;
} }
Future<String> 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<void> 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);
}
} }

37
lib/theme_bloc.dart Normal file
View File

@ -0,0 +1,37 @@
import 'package:calodiary/storage/storage.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ThemeDataBloc extends Bloc<ThemeToggleEvent, ThemeState> {
final AppStorage storage;
ThemeDataBloc(super.initialState, {required this.storage}) {
on<ThemeToggleEvent>(switchTheme);
}
void switchTheme(ThemeToggleEvent event, Emitter<ThemeState> 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<String> getPersistedTheme() async {
return storage.readBrightness();
}
}
class ThemeToggleEvent {
ThemeToggleEvent();
}
class ThemeState {
final String brightness;
ThemeState({required this.brightness});
}

View File

@ -442,6 +442,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" 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: uuid:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -18,6 +18,7 @@ dependencies:
path_provider: ^2.1.3 path_provider: ^2.1.3
quiver: ^3.2.1 quiver: ^3.2.1
settings_ui: ^2.0.2 settings_ui: ^2.0.2
universal_platform: ^1.1.0
uuid: ^4.4.0 uuid: ^4.4.0
dev_dependencies: dev_dependencies: