Skip to content

Commit

Permalink
add: theme data persist using shared_preferences
Browse files Browse the repository at this point in the history
  • Loading branch information
aliwaseem27 committed Sep 26, 2024
1 parent 15e9b51 commit c2f7afb
Show file tree
Hide file tree
Showing 12 changed files with 210 additions and 62 deletions.
2 changes: 1 addition & 1 deletion lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class MyApp extends StatelessWidget {
return MultiBlocProvider(
providers: [
BlocProvider<ThemeBloc>(
create: (context) => getIt<ThemeBloc>(),
create: (context) => getIt<ThemeBloc>()..add(const ThemeEvent.loadTheme()),
),
BlocProvider<LanguageBloc>(
create: (context) => getIt<LanguageBloc>()..add(LanguageEvent.loadInitialLocal(context)),
Expand Down
55 changes: 0 additions & 55 deletions lib/app.dart~

This file was deleted.

4 changes: 4 additions & 0 deletions lib/features/domain/repositories/theme_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
abstract class ThemeRepository {
Future<void> saveTheme(bool isDarkTheme);
Future<bool> loadTheme();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:injectable/injectable.dart';
import 'package:shared_preferences/shared_preferences.dart';

@injectable
class ThemeLocalDataSource {
final SharedPreferences sharedPreferences;
static const String _themeKey = 'THEME_MODE';

ThemeLocalDataSource(this.sharedPreferences);

Future<void> cacheTheme(bool isDarkTheme) async {
await sharedPreferences.setBool(_themeKey, isDarkTheme);
}

Future<bool> getTheme() async {
return sharedPreferences.getBool(_themeKey) ?? false; // false for light theme
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:injectable/injectable.dart';

import '../../domain/repositories/theme_repository.dart';
import '../datasources/theme_local_datasource.dart';

@LazySingleton(as: ThemeRepository)
class ThemeRepositoryImpl implements ThemeRepository {
final ThemeLocalDataSource localDataSource;

ThemeRepositoryImpl(this.localDataSource);

@override
Future<void> saveTheme(bool isDarkTheme) async {
await localDataSource.cacheTheme(isDarkTheme);
}

@override
Future<bool> loadTheme() async {
return await localDataSource.getTheme();
}
}
18 changes: 16 additions & 2 deletions lib/features/presentation/blocs/theme_bloc/theme_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:akkooo_todo/core/themes/theme.dart';
import 'package:akkooo_todo/features/domain/repositories/theme_repository.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
Expand All @@ -12,10 +13,23 @@ part 'theme_bloc.freezed.dart';

@injectable
class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
ThemeBloc() : super(const ThemeState.light()) {
on<_ToggleThemeEvent>((event, emit) {
final ThemeRepository _themeRepository;

ThemeBloc(this._themeRepository) : super(const ThemeState.light()) {
on<_ToggleThemeEvent>((event, emit) async {
if (state is _LightTheme) {
emit(const ThemeState.dark());
await _themeRepository.saveTheme(true);
} else {
emit(const ThemeState.light());
await _themeRepository.saveTheme(false);
}
});

on<_LoadThemeEvent>((event, emit) async {
final isDarkTheme = await _themeRepository.loadTheme();
if (isDarkTheme) {
emit(const ThemeState.dark());
} else {
emit(const ThemeState.light());
}
Expand Down
117 changes: 117 additions & 0 deletions lib/features/presentation/blocs/theme_bloc/theme_bloc.freezed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,38 @@ mixin _$ThemeEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() toggle,
required TResult Function() loadTheme,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? toggle,
TResult? Function()? loadTheme,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? toggle,
TResult Function()? loadTheme,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_ToggleThemeEvent value) toggle,
required TResult Function(_LoadThemeEvent value) loadTheme,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_ToggleThemeEvent value)? toggle,
TResult? Function(_LoadThemeEvent value)? loadTheme,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_ToggleThemeEvent value)? toggle,
TResult Function(_LoadThemeEvent value)? loadTheme,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
Expand Down Expand Up @@ -113,6 +119,7 @@ class _$ToggleThemeEventImpl implements _ToggleThemeEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() toggle,
required TResult Function() loadTheme,
}) {
return toggle();
}
Expand All @@ -121,6 +128,7 @@ class _$ToggleThemeEventImpl implements _ToggleThemeEvent {
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? toggle,
TResult? Function()? loadTheme,
}) {
return toggle?.call();
}
Expand All @@ -129,6 +137,7 @@ class _$ToggleThemeEventImpl implements _ToggleThemeEvent {
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? toggle,
TResult Function()? loadTheme,
required TResult orElse(),
}) {
if (toggle != null) {
Expand All @@ -141,6 +150,7 @@ class _$ToggleThemeEventImpl implements _ToggleThemeEvent {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_ToggleThemeEvent value) toggle,
required TResult Function(_LoadThemeEvent value) loadTheme,
}) {
return toggle(this);
}
Expand All @@ -149,6 +159,7 @@ class _$ToggleThemeEventImpl implements _ToggleThemeEvent {
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_ToggleThemeEvent value)? toggle,
TResult? Function(_LoadThemeEvent value)? loadTheme,
}) {
return toggle?.call(this);
}
Expand All @@ -157,6 +168,7 @@ class _$ToggleThemeEventImpl implements _ToggleThemeEvent {
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_ToggleThemeEvent value)? toggle,
TResult Function(_LoadThemeEvent value)? loadTheme,
required TResult orElse(),
}) {
if (toggle != null) {
Expand All @@ -170,6 +182,111 @@ abstract class _ToggleThemeEvent implements ThemeEvent {
const factory _ToggleThemeEvent() = _$ToggleThemeEventImpl;
}

/// @nodoc
abstract class _$$LoadThemeEventImplCopyWith<$Res> {
factory _$$LoadThemeEventImplCopyWith(_$LoadThemeEventImpl value,
$Res Function(_$LoadThemeEventImpl) then) =
__$$LoadThemeEventImplCopyWithImpl<$Res>;
}

/// @nodoc
class __$$LoadThemeEventImplCopyWithImpl<$Res>
extends _$ThemeEventCopyWithImpl<$Res, _$LoadThemeEventImpl>
implements _$$LoadThemeEventImplCopyWith<$Res> {
__$$LoadThemeEventImplCopyWithImpl(
_$LoadThemeEventImpl _value, $Res Function(_$LoadThemeEventImpl) _then)
: super(_value, _then);

/// Create a copy of ThemeEvent
/// with the given fields replaced by the non-null parameter values.
}

/// @nodoc
class _$LoadThemeEventImpl implements _LoadThemeEvent {
const _$LoadThemeEventImpl();

@override
String toString() {
return 'ThemeEvent.loadTheme()';
}

@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$LoadThemeEventImpl);
}

@override
int get hashCode => runtimeType.hashCode;

@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() toggle,
required TResult Function() loadTheme,
}) {
return loadTheme();
}

@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? toggle,
TResult? Function()? loadTheme,
}) {
return loadTheme?.call();
}

@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? toggle,
TResult Function()? loadTheme,
required TResult orElse(),
}) {
if (loadTheme != null) {
return loadTheme();
}
return orElse();
}

@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_ToggleThemeEvent value) toggle,
required TResult Function(_LoadThemeEvent value) loadTheme,
}) {
return loadTheme(this);
}

@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_ToggleThemeEvent value)? toggle,
TResult? Function(_LoadThemeEvent value)? loadTheme,
}) {
return loadTheme?.call(this);
}

@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_ToggleThemeEvent value)? toggle,
TResult Function(_LoadThemeEvent value)? loadTheme,
required TResult orElse(),
}) {
if (loadTheme != null) {
return loadTheme(this);
}
return orElse();
}
}

abstract class _LoadThemeEvent implements ThemeEvent {
const factory _LoadThemeEvent() = _$LoadThemeEventImpl;
}

/// @nodoc
mixin _$ThemeState {
@optionalTypeArgs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ part of 'theme_bloc.dart';
@freezed
class ThemeEvent with _$ThemeEvent {
const factory ThemeEvent.toggle() = _ToggleThemeEvent;
const factory ThemeEvent.loadTheme() = _LoadThemeEvent;
}
8 changes: 8 additions & 0 deletions lib/injectable_modules.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'package:injectable/injectable.dart';
import 'package:shared_preferences/shared_preferences.dart';

@module
abstract class InjectableModules {
@preResolve
Future<SharedPreferences> get prefs => SharedPreferences.getInstance();
}
Loading

0 comments on commit c2f7afb

Please sign in to comment.