From 2cf9bf48102f15449ca6da5d148da61cc999311c Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Fri, 15 Jan 2021 19:41:55 +0100 Subject: [PATCH] refactor: Use adaptive_theme --- lib/components/list_items/chat_list_item.dart | 4 +- lib/components/settings_themes.dart | 83 ------ lib/components/theme_switcher.dart | 276 ------------------ lib/config/themes.dart | 90 ++++++ lib/main.dart | 89 +++--- lib/views/settings_style.dart | 38 ++- pubspec.lock | 18 +- pubspec.yaml | 3 + 8 files changed, 191 insertions(+), 410 deletions(-) delete mode 100644 lib/components/settings_themes.dart delete mode 100644 lib/components/theme_switcher.dart create mode 100644 lib/config/themes.dart diff --git a/lib/components/list_items/chat_list_item.dart b/lib/components/list_items/chat_list_item.dart index 0559e294..449c9827 100644 --- a/lib/components/list_items/chat_list_item.dart +++ b/lib/components/list_items/chat_list_item.dart @@ -1,6 +1,7 @@ import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:circular_check_box/circular_check_box.dart'; import 'package:famedlysdk/famedlysdk.dart'; +import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/utils/event_extension.dart'; import 'package:fluffychat/utils/matrix_locals.dart'; import 'package:fluffychat/utils/room_status_extension.dart'; @@ -18,7 +19,6 @@ import '../dialogs/send_file_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import '../matrix.dart'; import '../mouse_over_builder.dart'; -import '../theme_switcher.dart'; enum ArchivedRoomAction { delete, rejoin } @@ -142,7 +142,7 @@ class ChatListItem extends StatelessWidget { room.lastEvent?.senderId == Matrix.of(context).client.userID; return Center( child: Material( - color: chatListItemColor(context, activeChat, selected), + color: FluffyThemes.chatListItemColor(context, activeChat, selected), child: ListTile( onLongPress: onLongPress, leading: MouseOverBuilder( diff --git a/lib/components/settings_themes.dart b/lib/components/settings_themes.dart deleted file mode 100644 index 61a6b67d..00000000 --- a/lib/components/settings_themes.dart +++ /dev/null @@ -1,83 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/l10n.dart'; - -import '../components/matrix.dart'; -import '../components/theme_switcher.dart'; - -class ThemesSettings extends StatefulWidget { - @override - ThemesSettingsState createState() => ThemesSettingsState(); -} - -class ThemesSettingsState extends State { - Themes _selectedTheme; - bool _amoledEnabled; - - @override - Widget build(BuildContext context) { - final matrix = Matrix.of(context); - final themeEngine = ThemeSwitcherWidget.of(context); - _selectedTheme = themeEngine.selectedTheme; - _amoledEnabled = themeEngine.amoledEnabled; - - return Column( - children: [ - RadioListTile( - title: Text( - L10n.of(context).systemTheme, - ), - value: Themes.system, - groupValue: _selectedTheme, - activeColor: Theme.of(context).primaryColor, - onChanged: (Themes value) { - setState(() { - _selectedTheme = value; - themeEngine.switchTheme(matrix, value, _amoledEnabled); - }); - }, - ), - RadioListTile( - title: Text( - L10n.of(context).lightTheme, - ), - value: Themes.light, - groupValue: _selectedTheme, - activeColor: Theme.of(context).primaryColor, - onChanged: (Themes value) { - setState(() { - _selectedTheme = value; - themeEngine.switchTheme(matrix, value, _amoledEnabled); - }); - }, - ), - RadioListTile( - title: Text( - L10n.of(context).darkTheme, - ), - value: Themes.dark, - groupValue: _selectedTheme, - activeColor: Theme.of(context).primaryColor, - onChanged: (Themes value) { - setState(() { - _selectedTheme = value; - themeEngine.switchTheme(matrix, value, _amoledEnabled); - }); - }, - ), - SwitchListTile( - title: Text( - L10n.of(context).useAmoledTheme, - ), - value: _amoledEnabled, - activeColor: Theme.of(context).primaryColor, - onChanged: (bool value) { - setState(() { - _amoledEnabled = value; - themeEngine.switchTheme(matrix, _selectedTheme, value); - }); - }, - ), - ], - ); - } -} diff --git a/lib/components/theme_switcher.dart b/lib/components/theme_switcher.dart deleted file mode 100644 index 1284d758..00000000 --- a/lib/components/theme_switcher.dart +++ /dev/null @@ -1,276 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'matrix.dart'; -import '../config/setting_keys.dart'; - -enum Themes { - light, - dark, - system, -} - -final ThemeData lightTheme = ThemeData( - primaryColorDark: Colors.white, - primaryColorLight: Color(0xff121212), - brightness: Brightness.light, - primaryColor: Color(0xFF5625BA), - backgroundColor: Colors.white, - secondaryHeaderColor: Color(0xFFECECF2), - scaffoldBackgroundColor: Colors.white, - snackBarTheme: SnackBarThemeData( - behavior: kIsWeb ? SnackBarBehavior.floating : SnackBarBehavior.fixed, - ), - dialogTheme: DialogTheme( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - ), - popupMenuTheme: PopupMenuThemeData( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - ), - appBarTheme: AppBarTheme( - brightness: Brightness.light, - color: Colors.white, - textTheme: TextTheme( - headline6: TextStyle( - color: Colors.black, - fontSize: 20, - ), - ), - iconTheme: IconThemeData(color: Colors.black), - ), -); - -final ThemeData darkTheme = ThemeData.dark().copyWith( - primaryColorDark: Color(0xff1B1B1B), - primaryColorLight: Colors.white, - primaryColor: Color(0xFF8966CF), - errorColor: Color(0xFFCF6679), - backgroundColor: Color(0xff121212), - scaffoldBackgroundColor: Color(0xff1B1B1B), - accentColor: Color(0xFFF5B4D2), - secondaryHeaderColor: Color(0xff202020), - snackBarTheme: SnackBarThemeData( - behavior: kIsWeb ? SnackBarBehavior.floating : SnackBarBehavior.fixed, - ), - dialogTheme: DialogTheme( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - ), - popupMenuTheme: PopupMenuThemeData( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - ), - appBarTheme: AppBarTheme( - brightness: Brightness.dark, - color: Color(0xff1D1D1D), - textTheme: TextTheme( - headline6: TextStyle( - color: Colors.white, - fontSize: 20, - ), - ), - iconTheme: IconThemeData(color: Colors.white), - ), -); - -final ThemeData amoledTheme = ThemeData.dark().copyWith( - primaryColorDark: Color(0xff121212), - primaryColorLight: Colors.white, - primaryColor: Color(0xFF8966CF), - errorColor: Color(0xFFCF6679), - backgroundColor: Colors.black, - scaffoldBackgroundColor: Colors.black, - accentColor: Color(0xFFF5B4D2), - secondaryHeaderColor: Color(0xff1D1D1D), - snackBarTheme: SnackBarThemeData( - behavior: kIsWeb ? SnackBarBehavior.floating : SnackBarBehavior.fixed, - ), - dialogTheme: DialogTheme( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - ), - popupMenuTheme: PopupMenuThemeData( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - ), - appBarTheme: AppBarTheme( - brightness: Brightness.dark, - color: Color(0xff1D1D1D), - textTheme: TextTheme( - headline6: TextStyle( - color: Colors.white, - fontSize: 20, - ), - ), - iconTheme: IconThemeData(color: Colors.white), - ), -); - -Color chatListItemColor(BuildContext context, bool activeChat, bool selected) => - selected - ? Theme.of(context).primaryColor.withAlpha(100) - : Theme.of(context).brightness == Brightness.light - ? activeChat - ? Color(0xFFE8E8E8) - : Colors.white - : activeChat - ? ThemeSwitcherWidget.of(context).amoledEnabled - ? Color(0xff121212) - : Colors.black - : ThemeSwitcherWidget.of(context).amoledEnabled - ? Colors.black - : Color(0xff121212); - -Color blackWhiteColor(BuildContext context) => - Theme.of(context).brightness == Brightness.light - ? Colors.white - : Colors.black; - -class ThemeSwitcher extends InheritedWidget { - final ThemeSwitcherWidgetState data; - - const ThemeSwitcher({ - Key key, - @required this.data, - @required Widget child, - }) : assert(child != null), - super(key: key, child: child); - - @override - bool updateShouldNotify(ThemeSwitcher old) { - return this != old; - } -} - -class ThemeSwitcherWidget extends StatefulWidget { - final Widget child; - - ThemeSwitcherWidget({Key key, @required this.child}) - : assert(child != null), - super(key: key); - - @override - ThemeSwitcherWidgetState createState() => ThemeSwitcherWidgetState(); - - /// Returns the (nearest) Client instance of your application. - static ThemeSwitcherWidgetState of(BuildContext context) { - var newState = - (context.dependOnInheritedWidgetOfExactType()).data; - newState.context = context; - return newState; - } -} - -class ThemeSwitcherWidgetState extends State { - ThemeData themeData; - Themes selectedTheme; - bool amoledEnabled; - @override - BuildContext context; - - Future loadSelection(MatrixState matrix) async { - var item = await matrix.store.getItem(SettingKeys.theme) ?? 'system'; - selectedTheme = Themes.values.firstWhere( - (e) => e.toString() == 'Themes.' + item, - orElse: () => Themes.system); - - amoledEnabled = await matrix.store.getItemBool(SettingKeys.amoledEnabled); - - switchTheme(matrix, selectedTheme, amoledEnabled); - return; - } - - void switchTheme( - MatrixState matrix, Themes newTheme, bool amoled_enabled) async { - ThemeData theme; - switch (newTheme) { - case Themes.light: - theme = lightTheme; - break; - case Themes.dark: - if (amoled_enabled) { - theme = amoledTheme; - } else { - theme = darkTheme; - } - break; - case Themes.system: - // This needs to be a low level call as we don't have a MaterialApp yet - var brightness = - MediaQueryData.fromWindow(WidgetsBinding.instance.window) - .platformBrightness; - if (brightness == Brightness.dark) { - if (amoled_enabled) { - theme = amoledTheme; - } else { - theme = darkTheme; - } - } else { - theme = lightTheme; - } - break; - } - - await saveThemeValue(matrix, newTheme); - await saveAmoledEnabledValue(matrix, amoled_enabled); - setState(() { - amoledEnabled = amoled_enabled; - selectedTheme = newTheme; - themeData = theme; - }); - } - - Future saveThemeValue(MatrixState matrix, Themes value) async { - await matrix.store - .setItem(SettingKeys.theme, value.toString().split('.').last); - } - - Future saveAmoledEnabledValue(MatrixState matrix, bool value) async { - await matrix.store.setItem(SettingKeys.amoledEnabled, value.toString()); - } - - void setup() async { - final matrix = Matrix.of(context); - await loadSelection(matrix); - } - - @override - void initState() { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (amoledEnabled == null || selectedTheme == null) { - setup(); - } - }); - super.initState(); - } - - @override - Widget build(BuildContext context) { - if (themeData == null) { - // This needs to be a low level call as we don't have a MaterialApp yet - var brightness = MediaQueryData.fromWindow(WidgetsBinding.instance.window) - .platformBrightness; - if (brightness == Brightness.dark) { - themeData = darkTheme; - } else { - themeData = lightTheme; - } - return ThemeSwitcher( - data: this, - child: widget.child, - ); - } else { - return ThemeSwitcher( - data: this, - child: widget.child, - ); - } - } -} diff --git a/lib/config/themes.dart b/lib/config/themes.dart new file mode 100644 index 00000000..58d147ad --- /dev/null +++ b/lib/config/themes.dart @@ -0,0 +1,90 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +abstract class FluffyThemes { + static ThemeData light = ThemeData( + primaryColorDark: Colors.white, + primaryColorLight: Color(0xff121212), + brightness: Brightness.light, + primaryColor: Color(0xFF5625BA), + backgroundColor: Colors.white, + secondaryHeaderColor: Color(0xFFECECF2), + scaffoldBackgroundColor: Colors.white, + snackBarTheme: SnackBarThemeData( + behavior: kIsWeb ? SnackBarBehavior.floating : SnackBarBehavior.fixed, + ), + dialogTheme: DialogTheme( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + ), + popupMenuTheme: PopupMenuThemeData( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + ), + appBarTheme: AppBarTheme( + brightness: Brightness.light, + color: Colors.white, + textTheme: TextTheme( + headline6: TextStyle( + color: Colors.black, + fontSize: 20, + ), + ), + iconTheme: IconThemeData(color: Colors.black), + ), + ); + + static ThemeData dark = ThemeData.dark().copyWith( + primaryColorDark: Color(0xff121212), + primaryColorLight: Colors.white, + primaryColor: Color(0xFF8966CF), + errorColor: Color(0xFFCF6679), + backgroundColor: Colors.black, + scaffoldBackgroundColor: Colors.black, + accentColor: Color(0xFFF5B4D2), + secondaryHeaderColor: Color(0xff1D1D1D), + snackBarTheme: SnackBarThemeData( + behavior: kIsWeb ? SnackBarBehavior.floating : SnackBarBehavior.fixed, + ), + dialogTheme: DialogTheme( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + ), + popupMenuTheme: PopupMenuThemeData( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + ), + appBarTheme: AppBarTheme( + brightness: Brightness.dark, + color: Color(0xff1D1D1D), + textTheme: TextTheme( + headline6: TextStyle( + color: Colors.white, + fontSize: 20, + ), + ), + iconTheme: IconThemeData(color: Colors.white), + ), + ); + + static Color chatListItemColor( + BuildContext context, bool activeChat, bool selected) => + selected + ? Theme.of(context).primaryColor.withAlpha(100) + : Theme.of(context).brightness == Brightness.light + ? activeChat + ? Color(0xFFE8E8E8) + : Colors.white + : activeChat + ? Color(0xff121212) + : Colors.black; + + static Color blackWhiteColor(BuildContext context) => + Theme.of(context).brightness == Brightness.light + ? Colors.white + : Colors.black; +} diff --git a/lib/main.dart b/lib/main.dart index e4e382ba..7f1df9be 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ // @dart=2.9 import 'dart:async'; +import 'package:adaptive_theme/adaptive_theme.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/utils/sentry_controller.dart'; import 'package:fluffychat/views/homeserver_picker.dart'; @@ -13,7 +14,7 @@ import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:universal_html/prefer_universal/html.dart' as html; import 'components/matrix.dart'; -import 'components/theme_switcher.dart'; +import 'config/themes.dart'; import 'utils/localized_exception_extension.dart'; import 'app_config.dart'; import 'views/chat_list.dart'; @@ -34,51 +35,49 @@ class App extends StatelessWidget { Widget build(BuildContext context) { return Matrix( child: Builder( - builder: (BuildContext context) => ThemeSwitcherWidget( - child: Builder( - builder: (context) => MaterialApp( - title: '${AppConfig.applicationName}', - theme: ThemeSwitcherWidget.of(context).themeData, - localizationsDelegates: L10n.localizationsDelegates, - supportedLocales: L10n.supportedLocales, - locale: kIsWeb - ? Locale( - html.window.navigator.language.split('-').first) - : null, - home: FutureBuilder( - future: Matrix.of(context) - .client - .onLoginStateChanged - .stream - .first, - builder: (context, snapshot) { - LoadingDialog.defaultTitle = - L10n.of(context).loadingPleaseWait; - LoadingDialog.defaultBackLabel = L10n.of(context).close; - LoadingDialog.defaultOnError = - (Object e) => e.toLocalizedString(context); - if (snapshot.hasError) { - WidgetsBinding.instance.addPostFrameCallback((_) => - FlushbarHelper.createError( - title: L10n.of(context).oopsSomethingWentWrong, - message: snapshot.error.toString(), - ).show(context)); - return HomeserverPicker(); - } - if (!snapshot.hasData) { - return Scaffold( - body: Center( - child: CircularProgressIndicator(), - ), - ); - } - if (Matrix.of(context).client.isLogged()) { - return ChatListView(); - } - return HomeserverPicker(); - }, + builder: (BuildContext context) => AdaptiveTheme( + light: FluffyThemes.light, + dark: FluffyThemes.dark, + initial: AdaptiveThemeMode.system, + builder: (theme, darkTheme) => MaterialApp( + title: '${AppConfig.applicationName}', + theme: theme, + darkTheme: darkTheme, + localizationsDelegates: L10n.localizationsDelegates, + supportedLocales: L10n.supportedLocales, + locale: kIsWeb + ? Locale(html.window.navigator.language.split('-').first) + : null, + home: FutureBuilder( + future: + Matrix.of(context).client.onLoginStateChanged.stream.first, + builder: (context, snapshot) { + LoadingDialog.defaultTitle = L10n.of(context).loadingPleaseWait; + LoadingDialog.defaultBackLabel = L10n.of(context).close; + LoadingDialog.defaultOnError = + (Object e) => e.toLocalizedString(context); + if (snapshot.hasError) { + WidgetsBinding.instance + .addPostFrameCallback((_) => FlushbarHelper.createError( + title: L10n.of(context).oopsSomethingWentWrong, + message: snapshot.error.toString(), + ).show(context)); + return HomeserverPicker(); + } + if (!snapshot.hasData) { + return Scaffold( + body: Center( + child: CircularProgressIndicator(), ), - )), + ); + } + if (Matrix.of(context).client.isLogged()) { + return ChatListView(); + } + return HomeserverPicker(); + }, + ), + ), ), ), ); diff --git a/lib/views/settings_style.dart b/lib/views/settings_style.dart index 80b8c7c8..ab40ada0 100644 --- a/lib/views/settings_style.dart +++ b/lib/views/settings_style.dart @@ -1,7 +1,7 @@ import 'dart:io'; +import 'package:adaptive_theme/adaptive_theme.dart'; import 'package:fluffychat/components/adaptive_page_layout.dart'; -import 'package:fluffychat/components/settings_themes.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -43,6 +43,23 @@ class _SettingsStyleState extends State { setState(() => null); } + AdaptiveThemeMode _currentTheme; + + void _switchTheme(AdaptiveThemeMode newTheme, BuildContext context) { + switch (newTheme) { + case AdaptiveThemeMode.light: + AdaptiveTheme.of(context).setLight(); + break; + case AdaptiveThemeMode.dark: + AdaptiveTheme.of(context).setDark(); + break; + case AdaptiveThemeMode.system: + AdaptiveTheme.of(context).setSystem(); + break; + } + setState(() => _currentTheme = newTheme); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -51,7 +68,24 @@ class _SettingsStyleState extends State { ), body: ListView( children: [ - ThemesSettings(), + RadioListTile( + groupValue: _currentTheme, + value: AdaptiveThemeMode.system, + title: Text(L10n.of(context).systemTheme), + onChanged: (t) => _switchTheme(t, context), + ), + RadioListTile( + groupValue: _currentTheme, + value: AdaptiveThemeMode.light, + title: Text(L10n.of(context).lightTheme), + onChanged: (t) => _switchTheme(t, context), + ), + RadioListTile( + groupValue: _currentTheme, + value: AdaptiveThemeMode.dark, + title: Text(L10n.of(context).darkTheme), + onChanged: (t) => _switchTheme(t, context), + ), Divider(thickness: 1), ListTile( title: Text( diff --git a/pubspec.lock b/pubspec.lock index c5f4d79f..37e2e02e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -15,6 +15,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.9.3" + adaptive_page_layout: + dependency: "direct main" + description: + name: adaptive_page_layout + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.6" + adaptive_theme: + dependency: "direct main" + description: + name: adaptive_theme + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" analyzer: dependency: transitive description: @@ -831,12 +845,12 @@ packages: source: hosted version: "3.0.13" provider: - dependency: transitive + dependency: "direct main" description: name: provider url: "https://pub.dartlang.org" source: hosted - version: "4.3.2+2" + version: "4.3.2+4" pub_semver: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index abdab50c..9ba9901a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,6 +22,9 @@ dependencies: cached_network_image: ^2.5.0 firebase_messaging: ^7.0.3 flutter_local_notifications: ^3.0.3 + adaptive_page_layout: ^0.1.6 + provider: ^4.3.2+4 + adaptive_theme: ^1.1.0 # desktop_notifications: ^0.0.0-dev.4 // Currently blocked by: https://github.com/canonical/desktop_notifications.dart/issues/5 matrix_link_text: ^0.3.2 path_provider: ^1.6.27