mirror of
https://github.com/inventree/inventree-app.git
synced 2025-07-01 03:10:46 +00:00
feat: theme update (#645)
This commit is contained in:
@ -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);
|
||||
|
@ -166,7 +166,7 @@ class InvenTreeAppState extends State<StatefulWidget> {
|
||||
colorSchemeSeed: Colors.blue,
|
||||
useMaterial3: true,
|
||||
),
|
||||
initial: savedThemeMode ?? AdaptiveThemeMode.light,
|
||||
initial: savedThemeMode ?? AdaptiveThemeMode.system,
|
||||
builder: (light, dark) => MaterialApp(
|
||||
theme: light,
|
||||
darkTheme: dark,
|
||||
|
@ -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<AdaptiveThemeMode>(
|
||||
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<AdaptiveThemeMode>(
|
||||
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<AdaptiveThemeMode>(
|
||||
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<Widget> drawerTiles(BuildContext context) {
|
||||
List<Widget> 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),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -225,10 +225,9 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage>
|
||||
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<InvenTreeHomePage>
|
||||
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,
|
||||
),
|
||||
|
@ -72,7 +72,7 @@ mixin BaseWidgetProperties {
|
||||
BuildContext context,
|
||||
GlobalKey<ScaffoldState> key,
|
||||
) {
|
||||
const double iconSize = 40;
|
||||
const double iconSize = 32;
|
||||
|
||||
List<Widget> icons = [
|
||||
IconButton(
|
||||
|
Reference in New Issue
Block a user