Skip to content

Commit

Permalink
fix: theme-mode button fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
cevheri committed Dec 15, 2024
1 parent 9f42d68 commit 244f279
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 26 deletions.
8 changes: 6 additions & 2 deletions lib/configuration/local_storage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// It uses shared preferences and get storage to store data locally.
// It also contains the implementation of the cache for the application.

import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc_advance/configuration/app_logger.dart';
import 'package:get_storage/get_storage.dart';
Expand All @@ -24,19 +25,22 @@ class AppLocalStorageCached {
static late List<String>? roles;
static late String? language;
static late String? username;
static late String? theme;

static Future<void> loadCache() async {
_log.trace("Loading cache");
jwtToken = await AppLocalStorage().read(StorageKeys.jwtToken.name);
roles = await AppLocalStorage().read(StorageKeys.roles.name);
language = await AppLocalStorage().read(StorageKeys.language.name) ?? "en";
username = await AppLocalStorage().read(StorageKeys.username.name);
_log.trace("Loaded cache with username:{}, roles:{}, language:{}, jwtToken:{}", [username, roles, language, jwtToken]);
theme = await AppLocalStorage().read(StorageKeys.theme.name) ?? AdaptiveThemeMode.light.name;
_log.trace("Loaded cache with username:{}, roles:{}, language:{}, jwtToken:{}, theme:{}", [username, roles, language, jwtToken, theme]);
}
}

/// LocalStorage predefined keys
enum StorageKeys { jwtToken, roles, language, username }
enum StorageKeys { jwtToken, roles, language, username, theme }


/// Application Local Storage
///
Expand Down
4 changes: 2 additions & 2 deletions lib/main/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ class App extends StatelessWidget {
);
}

ThemeData _buildDarkTheme() => ThemeData(brightness: Brightness.dark, primarySwatch: Colors.blueGrey);
ThemeData _buildDarkTheme() => ThemeData(useMaterial3: false, brightness: Brightness.dark, primarySwatch: Colors.blueGrey);

ThemeData _buildLightTheme() => ThemeData(brightness: Brightness.light, colorSchemeSeed: Colors.blueGrey);
ThemeData _buildLightTheme() => ThemeData(useMaterial3: false, brightness: Brightness.light, colorSchemeSeed: Colors.blueGrey);

MultiBlocProvider _buildMultiBlocProvider(ThemeData light, ThemeData dark) {
return MultiBlocProvider(
Expand Down
8 changes: 7 additions & 1 deletion lib/main/main_local.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ void main() async {
initializeJsonMapper();
WidgetsFlutterBinding.ensureInitialized();

//TODO change to the system language(browser language)
const defaultLanguage = "en";
AppLocalStorage().setStorage(StorageType.sharedPreferences);
await AppLocalStorage().save(StorageKeys.language.name, defaultLanguage);
Expand All @@ -36,5 +37,10 @@ void main() async {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) {
runApp(const App(language: defaultLanguage, initialTheme: initialTheme));
});
log.info("Started App with local environment language: {} and theme: {}", [defaultLanguage, initialTheme.name]);

//TODO change to the system theme(browser theme)
final defaultThemeName = initialTheme.name;
await AppLocalStorage().save(StorageKeys.theme.name, defaultThemeName);

log.info("Started App with local environment language: {} and theme: {}", [defaultLanguage, defaultThemeName]);
}
7 changes: 6 additions & 1 deletion lib/main/main_prod.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,10 @@ void main() async {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) {
runApp(const App(language: defaultLanguage, initialTheme: initialTheme));
});
log.info("Started App with env: {} language: {} and theme: {}", [Environment.prod.name, defaultLanguage, initialTheme.name]);

//TODO change to the system theme(browser theme)
final defaultThemeName = initialTheme.name;
await AppLocalStorage().save(StorageKeys.theme.name, defaultThemeName);

log.info("Started App with local environment language: {} and theme: {}", [defaultLanguage, defaultThemeName]);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:async';

import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
Expand Down Expand Up @@ -30,6 +31,20 @@ class DrawerBloc extends Bloc<DrawerEvent, DrawerState> {
on<RefreshMenus>(_refreshMenus);
on<Logout>(_onLogout);
on<ChangeLanguageEvent>(_onChangeLanguage);
on<ChangeThemeEvent>(_onChangeTheme);
}

FutureOr<void> _onChangeTheme(ChangeThemeEvent event, Emitter<DrawerState> emit) async {
_log.debug("BEGIN: onChangeTheme ChangeThemeEvent event: {}", []);
emit(state.copyWith(theme: event.theme, status: DrawerStateStatus.loading));
try {
await AppLocalStorage().save(StorageKeys.theme.name, event.theme.name);
emit(state.copyWith(theme: event.theme, status: DrawerStateStatus.success));
_log.debug("END:onChangeTheme ChangeThemeEvent event success: {}", [event.theme]);
} catch (e) {
emit(state.copyWith(theme: event.theme, status: DrawerStateStatus.error));
_log.error("END:onChangeTheme ChangeThemeEvent event error: {}", [e.toString()]);
}
}

FutureOr<void> _onChangeLanguage(ChangeLanguageEvent event, Emitter<DrawerState> emit) async {
Expand Down Expand Up @@ -64,15 +79,20 @@ class DrawerBloc extends Bloc<DrawerEvent, DrawerState> {

FutureOr<void> _loadMenus(LoadMenus event, Emitter<DrawerState> emit) async {
_log.debug("BEGIN: loadMenus LoadMenus event: {}", []);
emit(state.copyWith(menus: [], status: DrawerStateStatus.loading, language: event.language));
emit(state.copyWith(
menus: [],
status: DrawerStateStatus.loading,
language: event.language,
theme: event.theme,
));
try {
if (MenuListCache.menus.isNotEmpty) {
emit(state.copyWith(menus: MenuListCache.menus, status: DrawerStateStatus.success));
_log.info("END:loadMenus read from cache: {}", []);
return;
}
final menus = await _menuRepository.getMenus();
if(menus.isEmpty) {
if (menus.isEmpty) {
emit(state.copyWith(menus: menus, status: DrawerStateStatus.error));
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ class Logout extends DrawerEvent {}

class LoadMenus extends DrawerEvent {
final String language;
final AdaptiveThemeMode theme;

const LoadMenus({required this.language});
const LoadMenus({required this.language, required this.theme});

@override
List<Object> get props => [language];
List<Object> get props => [language, theme];
}

class RefreshMenus extends DrawerEvent {}
Expand All @@ -28,3 +29,12 @@ class ChangeLanguageEvent extends DrawerEvent {
@override
List<Object> get props => [language];
}

class ChangeThemeEvent extends DrawerEvent {
final AdaptiveThemeMode theme;

const ChangeThemeEvent({required this.theme});

@override
List<Object> get props => [theme];
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,37 @@ class DrawerState extends Equatable {
final bool isLogout;
final DrawerStateStatus status;
final String? language;
final AdaptiveThemeMode? theme;

const DrawerState({
this.menus = const [],
this.isLogout = false,
this.status = DrawerStateStatus.initial,
this.language,
this.theme,
});

DrawerState copyWith({
List<Menu>? menus,
bool? isLogout,
DrawerStateStatus? status,
String? language,
AdaptiveThemeMode? theme,
}) {
return DrawerState(
menus: menus ?? this.menus,
isLogout: isLogout ?? this.isLogout,
status: status ?? this.status,
language: language ?? this.language,
theme: theme ?? this.theme,
);
}

@override
List<Object> get props => [status, menus, isLogout];
}

//TODO add default language and theme
class DrawerStateInitial extends DrawerState {
const DrawerStateInitial() : super(status: DrawerStateStatus.initial);
}
Expand All @@ -53,4 +58,8 @@ class DrawerStateError extends DrawerState {

class DrawerLanguageChanged extends DrawerState {
const DrawerLanguageChanged({required super.language}) : super(status: DrawerStateStatus.success);
}

class DrawerThemeChanged extends DrawerState {
const DrawerThemeChanged({required super.theme}) : super(status: DrawerStateStatus.success);
}
28 changes: 20 additions & 8 deletions lib/presentation/common_widgets/drawer/drawer_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class ApplicationDrawer extends StatelessWidget {

@override
Widget build(BuildContext context) {
debugPrint("ApplicationDrawer build");
return MultiBlocListener(
listeners: [
BlocListener<DrawerBloc, DrawerState>(
Expand All @@ -39,18 +40,22 @@ class ApplicationDrawer extends StatelessWidget {
],
child: BlocBuilder<DrawerBloc, DrawerState>(
builder: (context, state) {
final isDarkMode = AdaptiveTheme.of(context).mode.isDark;
final isDarkMode = state.theme == AdaptiveThemeMode.dark;

//debugPrint("BUILDER - current language : ${AppLocalStorageCached.language}");
//debugPrint("BUILDER - state language : ${state.language}");
// debugPrint("BUILDER - current lang : ${AppLocalStorageCached.language}");
// debugPrint("BUILDER - state lang : ${state.language}");
//
//
// debugPrint("BUILDER - current theme : ${AppLocalStorageCached.theme}");
// debugPrint("BUILDER - state theme : ${state.theme}");

var isEnglish = state.language == 'en';

final menuNodes = state.menus.where((e) => e.level == 1 && e.active).toList()
..sort((a, b) => a.orderPriority.compareTo(b.orderPriority));

return Drawer(
key: Key("drawer-${state.language}"),
key: Key("drawer-${state.language}-${state.theme}"),
child: SingleChildScrollView(
child: Column(
children: [
Expand All @@ -60,17 +65,24 @@ class ApplicationDrawer extends StatelessWidget {
key: const Key("drawer-switch-theme"),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(isDarkMode ? Icons.dark_mode : Icons.light_mode),
],
children: [Icon(isDarkMode ? Icons.dark_mode : Icons.light_mode)],
),
value: isDarkMode,
onChanged: (value) {
//debugPrint("BEGIN:ON_PRESSED.value - ${value}");
final newTheme = value ? AdaptiveThemeMode.dark : AdaptiveThemeMode.light;
//debugPrint("BEGIN:ON_PRESSED - current theme : ${AppLocalStorageCached.theme}");
//debugPrint("BEGIN:ON_PRESSED - current newTheme : ${newTheme}");
context.read<DrawerBloc>().add(ChangeThemeEvent(theme: newTheme));
if (value) {
AdaptiveTheme.of(context).setDark();
} else {
AdaptiveTheme.of(context).setLight();
}
Scaffold.of(context).closeDrawer();
AppRouter().push(context, ApplicationRoutesConstants.home);

//debugPrint("END:ON_PRESSED - current cached theme : ${AppLocalStorageCached.theme}");
},
),
const SizedBox(height: 20),
Expand All @@ -81,7 +93,7 @@ class ApplicationDrawer extends StatelessWidget {
children: [Text(isEnglish ? S.of(context).english : S.of(context).turkish)],
),
value: isEnglish,
onChanged: (value) async {
onChanged: (value) {
final newLang = value ? 'en' : 'tr';
context.read<DrawerBloc>().add(ChangeLanguageEvent(language: newLang));
AppRouter().push(context, ApplicationRoutesConstants.home);
Expand Down
16 changes: 13 additions & 3 deletions lib/presentation/screen/home/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class HomeScreen extends StatelessWidget {
}

Widget _buildBody(BuildContext context) {
//debugPrint("HomeScreen _buildBody");
debugPrint("HomeScreen _buildBody theme: ${AppLocalStorageCached.theme}");
return BlocProvider(
create: (context) {
//debugPrint("HomeScreen account blocProvider");
Expand All @@ -41,7 +41,7 @@ class HomeScreen extends StatelessWidget {
debugPrint("HomeScreen account bloc builder: ${state.status}");
if (state.status == AccountStatus.success) {
return Scaffold(
appBar: AppBar(title: const Text(AppConstants.appName)),
appBar: AppBar(title: const Text(AppConstants.appName),),
key: _scaffoldKey,
body: Center(child: Column(children: [backgroundImage(context)])),
drawer: _buildDrawer(context),
Expand Down Expand Up @@ -97,9 +97,19 @@ class HomeScreen extends StatelessWidget {
}

Widget _buildDrawer(BuildContext context) {
debugPrint("HomeScreen _buildDrawer : init-theme ${AppLocalStorageCached.theme}");
AdaptiveThemeMode initialAppThemeType;
if (AppLocalStorageCached.theme == 'light') {
initialAppThemeType = AdaptiveThemeMode.light;
} else {
initialAppThemeType = AdaptiveThemeMode.dark;
}
final initialAppLanguage = AppLocalStorageCached.language ?? 'en';
return BlocProvider<DrawerBloc>(
create: (context) => DrawerBloc(loginRepository: LoginRepository(), menuRepository: MenuRepository())
..add(LoadMenus(language: AppLocalStorageCached.language ?? 'en')),
..add(
LoadMenus(language: initialAppLanguage, theme: initialAppThemeType),
),
child: const ApplicationDrawer(),
);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/routes/go_router_routes/user_routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:go_router/go_router.dart';
class UserRoutes {
static final List<GoRoute> routes = [
GoRoute(name: 'userList', path: '/user', builder: (context, state) => ListUserScreen()),
GoRoute(name: 'userNew', path: '/user/new', builder: (context, state) => CreateUserScreen()),
GoRoute(name: 'userNew', path: '/user/new', builder: (context, state) => CreateUserScreen()), // UserUpdateScreen(new, edit, view)
GoRoute(name: 'userEdit', path: '/user/:id/edit', builder: (context, state) => EditUserScreen(id: state.pathParameters['id']!)),
//GoRoute(name: 'userView' , path: '/user/:id/view', builder: (context, state) => EditViewScreen(id: state.pathParameters['id']!)),
];
Expand Down
7 changes: 4 additions & 3 deletions test/presentation/blocs/drawer_bloc_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_bloc_advance/data/models/menu.dart';
import 'package:flutter_bloc_advance/data/repository/login_repository.dart';
Expand Down Expand Up @@ -55,12 +56,12 @@ void main() {
/// Drawer Event Tests
group("DrawerEvent", () {
test("supports value comparisons", () {
expect(const LoadMenus(language:"en"), const LoadMenus(language: "en"));
expect(const LoadMenus(language:"en", theme: AdaptiveThemeMode.light), const LoadMenus(language: "en", theme: AdaptiveThemeMode.light));
expect(RefreshMenus(), RefreshMenus());
expect(Logout(), Logout());
});
test("props", () {
expect(const LoadMenus(language: "en").props, []);
expect(const LoadMenus(language: "en", theme: AdaptiveThemeMode.light).props, ['en', AdaptiveThemeMode.light]);
expect(RefreshMenus().props, []);
expect(Logout().props, []);
});
Expand All @@ -76,7 +77,7 @@ void main() {
});
const input = [Menu(id: "test", name: "test")];
final output = Future.value(input);
const event = LoadMenus(language: "en");
const event = LoadMenus(language: "en", theme: AdaptiveThemeMode.light);
const loadingState = DrawerState(menus: [], status: DrawerStateStatus.loading);
const successState = DrawerState(menus: input, status: DrawerStateStatus.success);
const failureState = DrawerState(menus: [], status: DrawerStateStatus.error);
Expand Down
1 change: 0 additions & 1 deletion test/presentation/screen/home/home_screen_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc_advance/configuration/app_key_constants.dart';
import 'package:flutter_bloc_advance/configuration/local_storage.dart';
import 'package:flutter_bloc_advance/main/app.dart';
import 'package:flutter_bloc_advance/presentation/common_widgets/drawer/drawer_widget.dart';
import 'package:flutter_bloc_advance/presentation/screen/home/home_screen.dart';
import 'package:flutter_bloc_advance/presentation/screen/login/login_screen.dart';
import 'package:flutter_bloc_advance/utils/app_constants.dart';
Expand Down

0 comments on commit 244f279

Please sign in to comment.