diff --git a/lib/app_colors.dart b/lib/app_colors.dart index aeda838c..a22dfbc0 100644 --- a/lib/app_colors.dart +++ b/lib/app_colors.dart @@ -26,10 +26,8 @@ Color get COLOR_ACTION { } } -// Return an "app bar" color based on the current theme -Color get COLOR_APP_BAR { - return Color.fromRGBO(55, 150, 175, 1); -} +// Set to null to use the system default +Color? COLOR_APP_BAR; const Color COLOR_WARNING = Color.fromRGBO(250, 150, 50, 1); const Color COLOR_DANGER = Color.fromRGBO(200, 50, 75, 1); diff --git a/lib/main.dart b/lib/main.dart index 22dd25bb..5db07eeb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -166,7 +166,7 @@ class InvenTreeAppState extends State { colorSchemeSeed: Colors.blue, useMaterial3: true, ), - initial: savedThemeMode ?? AdaptiveThemeMode.light, + initial: savedThemeMode ?? AdaptiveThemeMode.system, builder: (light, dark) => MaterialApp( theme: light, darkTheme: dark, diff --git a/lib/widget/drawer.dart b/lib/widget/drawer.dart index 90bae321..9f30446e 100644 --- a/lib/widget/drawer.dart +++ b/lib/widget/drawer.dart @@ -19,6 +19,81 @@ import "package:inventree/widget/stock/location_display.dart"; /* * Custom "drawer" widget for the InvenTree app. */ +// Dialog for theme selection +class ThemeSelectionDialog extends StatelessWidget { + const ThemeSelectionDialog({Key? key, required this.onThemeSelected}) + : super(key: key); + + final VoidCallback onThemeSelected; + + @override + Widget build(BuildContext context) { + final currentThemeMode = AdaptiveTheme.of(context).mode; + + return AlertDialog( + title: Text(L10().colorScheme), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + RadioListTile( + title: Row( + children: [ + Icon(TablerIcons.device_desktop), + SizedBox(width: 10), + Text("System"), + ], + ), + value: AdaptiveThemeMode.system, + groupValue: currentThemeMode, + onChanged: (value) { + AdaptiveTheme.of(context).setThemeMode(AdaptiveThemeMode.system); + onThemeSelected(); + }, + ), + RadioListTile( + title: Row( + children: [ + Icon(TablerIcons.sun), + SizedBox(width: 10), + Text("Light"), + ], + ), + value: AdaptiveThemeMode.light, + groupValue: currentThemeMode, + onChanged: (value) { + AdaptiveTheme.of(context).setThemeMode(AdaptiveThemeMode.light); + onThemeSelected(); + }, + ), + RadioListTile( + title: Row( + children: [ + Icon(TablerIcons.moon), + SizedBox(width: 10), + Text("Dark"), + ], + ), + value: AdaptiveThemeMode.dark, + groupValue: currentThemeMode, + onChanged: (value) { + AdaptiveTheme.of(context).setThemeMode(AdaptiveThemeMode.dark); + onThemeSelected(); + }, + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text("Cancel"), + ), + ], + ); + } +} + class InvenTreeDrawer extends StatelessWidget { const InvenTreeDrawer(this.context); @@ -118,6 +193,18 @@ class InvenTreeDrawer extends StatelessWidget { ); } + // Return an icon representing the current theme mode + Widget _getThemeModeIcon(AdaptiveThemeMode mode) { + switch (mode) { + case AdaptiveThemeMode.dark: + return Icon(TablerIcons.moon); + case AdaptiveThemeMode.light: + return Icon(TablerIcons.sun); + case AdaptiveThemeMode.system: + return Icon(TablerIcons.device_desktop); + } + } + // Construct list of tiles to display in the "drawer" menu List drawerTiles(BuildContext context) { List tiles = []; @@ -125,7 +212,7 @@ class InvenTreeDrawer extends StatelessWidget { // "Home" access tiles.add( ListTile( - leading: Icon(TablerIcons.home, color: COLOR_ACTION), + leading: Image.asset("assets/image/logo_transparent.png", height: 24), title: Text( L10().appTitle, style: TextStyle(fontWeight: FontWeight.bold), @@ -195,18 +282,25 @@ class InvenTreeDrawer extends StatelessWidget { tiles.add(Divider()); - bool darkMode = AdaptiveTheme.of(context).mode.isDark; - tiles.add( ListTile( onTap: () { - AdaptiveTheme.of(context).toggleThemeMode(); - _closeDrawer(); + showDialog( + context: context, + builder: (BuildContext dialogContext) { + return ThemeSelectionDialog( + onThemeSelected: () { + Navigator.of(dialogContext).pop(); + _closeDrawer(); + }, + ); + }, + ); }, title: Text(L10().colorScheme), subtitle: Text(L10().colorSchemeDetail), - leading: Icon(TablerIcons.sun_moon, color: COLOR_ACTION), - trailing: Icon(darkMode ? TablerIcons.moon : TablerIcons.sun), + leading: Icon(TablerIcons.palette, color: COLOR_ACTION), + trailing: _getThemeModeIcon(AdaptiveTheme.of(context).mode), ), ); diff --git a/lib/widget/home.dart b/lib/widget/home.dart index 2a2b615d..3b29d868 100644 --- a/lib/widget/home.dart +++ b/lib/widget/home.dart @@ -225,10 +225,9 @@ class _InvenTreeHomePageState extends State child: ListTile( leading: Icon( icon, - size: 32, color: connected && allowed ? COLOR_ACTION : Colors.grey, ), - title: Text(label, style: TextStyle(fontSize: 20)), + title: Text(label), trailing: trailing, ), alignment: Alignment.center, @@ -457,15 +456,39 @@ class _InvenTreeHomePageState extends State return Scaffold( key: homeKey, appBar: AppBar( - title: Text(L10().appTitle), + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset("assets/image/logo_transparent.png", height: 24), + SizedBox(width: 8), + Text(L10().appTitle), + ], + ), backgroundColor: COLOR_APP_BAR, actions: [ IconButton( - icon: Icon( - TablerIcons.server, - color: connected - ? COLOR_SUCCESS - : (connecting ? COLOR_PROGRESS : COLOR_DANGER), + icon: Stack( + children: [ + Icon(TablerIcons.server), + Positioned( + right: 0, + bottom: 0, + child: Container( + width: 10, + height: 10, + decoration: BoxDecoration( + color: connected + ? COLOR_SUCCESS + : (connecting ? COLOR_PROGRESS : COLOR_DANGER), + shape: BoxShape.circle, + border: Border.all( + color: Theme.of(context).scaffoldBackgroundColor, + width: 1.5, + ), + ), + ), + ), + ], ), onPressed: _selectProfile, ), diff --git a/lib/widget/refreshable_state.dart b/lib/widget/refreshable_state.dart index 9b09c975..cd53b829 100644 --- a/lib/widget/refreshable_state.dart +++ b/lib/widget/refreshable_state.dart @@ -72,7 +72,7 @@ mixin BaseWidgetProperties { BuildContext context, GlobalKey key, ) { - const double iconSize = 40; + const double iconSize = 32; List icons = [ IconButton(