mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-10-31 13:25:40 +00:00 
			
		
		
		
	App orientation (#369)
* Configurable screen orientation - Follow system (default) - Fixed in portrait - Fixed in landscape * Fix for dialog
This commit is contained in:
		| @@ -627,6 +627,21 @@ | ||||
|   "onOrderDetails": "Items currently on order", | ||||
|   "@onOrderDetails": {}, | ||||
|  | ||||
|   "orientation": "Screen Orientation", | ||||
|   "@orientation": {}, | ||||
|  | ||||
|   "orientationDetail": "Screen orientation (requires restart)", | ||||
|   "@orientationDetail": {}, | ||||
|  | ||||
|   "orientationLandscape": "Landscape", | ||||
|   "@orientationLandscape": {}, | ||||
|    | ||||
|   "orientationPortrait": "Portrait", | ||||
|   "@orientationPortrait": {}, | ||||
|  | ||||
|   "orientationSystem": "System", | ||||
|   "@orientationSystem": {}, | ||||
|  | ||||
|   "outstanding": "Outstanding", | ||||
|   "@outstanding": {}, | ||||
|  | ||||
|   | ||||
| @@ -55,9 +55,29 @@ Future<void> main() async { | ||||
|       ); | ||||
|     }; | ||||
|  | ||||
|     runApp( | ||||
|       InvenTreeApp(savedThemeMode) | ||||
|     ); | ||||
|     final int orientation = await InvenTreeSettingsManager().getValue(INV_SCREEN_ORIENTATION, SCREEN_ORIENTATION_SYSTEM) as int; | ||||
|  | ||||
|     List<DeviceOrientation> orientations = []; | ||||
|  | ||||
|     switch (orientation) { | ||||
|       case SCREEN_ORIENTATION_PORTRAIT: | ||||
|         orientations.add(DeviceOrientation.portraitUp); | ||||
|         break; | ||||
|       case SCREEN_ORIENTATION_LANDSCAPE: | ||||
|         orientations.add(DeviceOrientation.landscapeLeft); | ||||
|         break; | ||||
|       default: | ||||
|         orientations.add(DeviceOrientation.portraitUp); | ||||
|         orientations.add(DeviceOrientation.landscapeLeft); | ||||
|         orientations.add(DeviceOrientation.landscapeRight); | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     SystemChrome.setPreferredOrientations(orientations).then((_) { | ||||
|       runApp( | ||||
|         InvenTreeApp(savedThemeMode) | ||||
|       ); | ||||
|     }); | ||||
|  | ||||
|   }, (Object error, StackTrace stackTrace) async { | ||||
|     sentryReportError("main.runZonedGuarded", error, stackTrace); | ||||
|   | ||||
| @@ -15,6 +15,13 @@ const String INV_HOME_SHOW_MANUFACTURERS = "homeShowManufacturers"; | ||||
| const String INV_HOME_SHOW_CUSTOMERS = "homeShowCustomers"; | ||||
| const String INV_HOME_SHOW_SUPPLIERS = "homeShowSuppliers"; | ||||
|  | ||||
| const String INV_SCREEN_ORIENTATION = "appScreenOrientation"; | ||||
|  | ||||
| // Available screen orientation values | ||||
| const int SCREEN_ORIENTATION_SYSTEM = 0; | ||||
| const int SCREEN_ORIENTATION_PORTRAIT = 1; | ||||
| const int SCREEN_ORIENTATION_LANDSCAPE = 2; | ||||
|  | ||||
| const String INV_SOUNDS_BARCODE = "barcodeSounds"; | ||||
| const String INV_SOUNDS_SERVER = "serverSounds"; | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,8 @@ import "package:flutter/material.dart"; | ||||
| import "package:adaptive_theme/adaptive_theme.dart"; | ||||
| import "package:font_awesome_flutter/font_awesome_flutter.dart"; | ||||
| import "package:flutter_localized_locales/flutter_localized_locales.dart"; | ||||
| import "package:inventree/app_colors.dart"; | ||||
| import "package:inventree/widget/dialogs.dart"; | ||||
| import "package:one_context/one_context.dart"; | ||||
|  | ||||
| import "package:inventree/api_form.dart"; | ||||
| @@ -34,6 +36,8 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> { | ||||
|  | ||||
|   bool darkMode = false; | ||||
|  | ||||
|   int screenOrientation = SCREEN_ORIENTATION_SYSTEM; | ||||
|  | ||||
|   Locale? locale; | ||||
|  | ||||
|   @override | ||||
| @@ -51,6 +55,7 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> { | ||||
|     serverSounds = await InvenTreeSettingsManager().getValue(INV_SOUNDS_SERVER, true) as bool; | ||||
|     reportErrors = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool; | ||||
|     strictHttps = await InvenTreeSettingsManager().getValue(INV_STRICT_HTTPS, false) as bool; | ||||
|     screenOrientation = await InvenTreeSettingsManager().getValue(INV_SCREEN_ORIENTATION, SCREEN_ORIENTATION_SYSTEM) as int; | ||||
|  | ||||
|     darkMode = AdaptiveTheme.of(context).mode.isDark; | ||||
|  | ||||
| @@ -116,9 +121,9 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> { | ||||
|         InvenTreeApp.of(context)?.setLocale(locale); | ||||
|       } | ||||
|     ); | ||||
|  | ||||
|   } | ||||
|  | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|  | ||||
| @@ -128,6 +133,21 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> { | ||||
|       languageName = LocaleNames.of(context)!.nameOf(locale.toString()) ?? L10().languageDefault; | ||||
|     } | ||||
|  | ||||
|     IconData orientationIcon = Icons.screen_rotation; | ||||
|  | ||||
|     switch (screenOrientation) { | ||||
|       case SCREEN_ORIENTATION_PORTRAIT: | ||||
|         orientationIcon = Icons.screen_lock_portrait; | ||||
|         break; | ||||
|       case SCREEN_ORIENTATION_LANDSCAPE: | ||||
|         orientationIcon = Icons.screen_lock_landscape; | ||||
|         break; | ||||
|       case SCREEN_ORIENTATION_SYSTEM: | ||||
|       default: | ||||
|         orientationIcon = Icons.screen_rotation; | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     return Scaffold( | ||||
|       key: _settingsKey, | ||||
|       appBar: AppBar( | ||||
| @@ -138,42 +158,6 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> { | ||||
|           children: [ | ||||
|             /* Sound Settings */ | ||||
|             Divider(height: 3), | ||||
|             ListTile( | ||||
|               title: Text( | ||||
|                 L10().sounds, | ||||
|                 style: TextStyle(fontWeight: FontWeight.bold), | ||||
|               ), | ||||
|               leading: FaIcon(FontAwesomeIcons.volumeHigh), | ||||
|             ), | ||||
|             ListTile( | ||||
|               title: Text(L10().serverError), | ||||
|               subtitle: Text(L10().soundOnServerError), | ||||
|               leading: FaIcon(FontAwesomeIcons.server), | ||||
|               trailing: Switch( | ||||
|                 value: serverSounds, | ||||
|                 onChanged: (bool value) { | ||||
|                   InvenTreeSettingsManager().setValue(INV_SOUNDS_SERVER, value); | ||||
|                   setState(() { | ||||
|                     serverSounds = value; | ||||
|                   }); | ||||
|                 }, | ||||
|               ), | ||||
|             ), | ||||
|             ListTile( | ||||
|               title: Text(L10().barcodeTones), | ||||
|               subtitle: Text(L10().soundOnBarcodeAction), | ||||
|               leading: Icon(Icons.qr_code), | ||||
|               trailing: Switch( | ||||
|                 value: barcodeSounds, | ||||
|                 onChanged: (bool value) { | ||||
|                   InvenTreeSettingsManager().setValue(INV_SOUNDS_BARCODE, value); | ||||
|                   setState(() { | ||||
|                     barcodeSounds = value; | ||||
|                   }); | ||||
|                 }, | ||||
|               ), | ||||
|             ), | ||||
|             Divider(height: 1), | ||||
|             ListTile( | ||||
|               title: Text( | ||||
|                 L10().appSettings, | ||||
| @@ -199,6 +183,41 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> { | ||||
|                 } | ||||
|               ) | ||||
|             ), | ||||
|             GestureDetector( | ||||
|               child: ListTile( | ||||
|                 title: Text(L10().orientation), | ||||
|                 subtitle: Text(L10().orientationDetail), | ||||
|                 leading: Icon(Icons.screen_rotation_alt), | ||||
|                 trailing: Icon(orientationIcon), | ||||
|               ), | ||||
|               onTap: () async { | ||||
|                 choiceDialog( | ||||
|                   L10().orientation, | ||||
|                   [ | ||||
|                     ListTile( | ||||
|                       leading: Icon(Icons.screen_rotation, color: screenOrientation == SCREEN_ORIENTATION_SYSTEM ? COLOR_ACTION : null), | ||||
|                       title: Text(L10().orientationSystem), | ||||
|                     ), | ||||
|                     ListTile( | ||||
|                       leading: Icon(Icons.screen_lock_portrait, color: screenOrientation == SCREEN_ORIENTATION_PORTRAIT ? COLOR_ACTION : null), | ||||
|                       title: Text(L10().orientationPortrait), | ||||
|                     ), | ||||
|                     ListTile( | ||||
|                       leading: Icon(Icons.screen_lock_landscape, color: screenOrientation == SCREEN_ORIENTATION_LANDSCAPE ? COLOR_ACTION : null), | ||||
|                       title: Text(L10().orientationLandscape), | ||||
|                     ) | ||||
|                   ], | ||||
|                   onSelected: (idx) async { | ||||
|                     screenOrientation = idx as int; | ||||
|  | ||||
|                     InvenTreeSettingsManager().setValue(INV_SCREEN_ORIENTATION, screenOrientation); | ||||
|  | ||||
|                     setState(() { | ||||
|                     }); | ||||
|                   } | ||||
|                 ); | ||||
|               }, | ||||
|             ), | ||||
|             ListTile( | ||||
|               title: Text(L10().strictHttps), | ||||
|               subtitle: Text(L10().strictHttpsDetails), | ||||
| @@ -235,6 +254,43 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> { | ||||
|                 }, | ||||
|               ), | ||||
|             ), | ||||
|                         ListTile( | ||||
|               title: Text( | ||||
|                 L10().sounds, | ||||
|                 style: TextStyle(fontWeight: FontWeight.bold), | ||||
|               ), | ||||
|               leading: FaIcon(FontAwesomeIcons.volumeHigh), | ||||
|             ), | ||||
|             Divider(), | ||||
|             ListTile( | ||||
|               title: Text(L10().serverError), | ||||
|               subtitle: Text(L10().soundOnServerError), | ||||
|               leading: FaIcon(FontAwesomeIcons.server), | ||||
|               trailing: Switch( | ||||
|                 value: serverSounds, | ||||
|                 onChanged: (bool value) { | ||||
|                   InvenTreeSettingsManager().setValue(INV_SOUNDS_SERVER, value); | ||||
|                   setState(() { | ||||
|                     serverSounds = value; | ||||
|                   }); | ||||
|                 }, | ||||
|               ), | ||||
|             ), | ||||
|             ListTile( | ||||
|               title: Text(L10().barcodeTones), | ||||
|               subtitle: Text(L10().soundOnBarcodeAction), | ||||
|               leading: Icon(Icons.qr_code), | ||||
|               trailing: Switch( | ||||
|                 value: barcodeSounds, | ||||
|                 onChanged: (bool value) { | ||||
|                   InvenTreeSettingsManager().setValue(INV_SOUNDS_BARCODE, value); | ||||
|                   setState(() { | ||||
|                     barcodeSounds = value; | ||||
|                   }); | ||||
|                 }, | ||||
|               ), | ||||
|             ), | ||||
|             Divider(height: 1), | ||||
|           ] | ||||
|         ) | ||||
|       ) | ||||
|   | ||||
| @@ -10,6 +10,51 @@ import "package:inventree/preferences.dart"; | ||||
| import "package:inventree/widget/snacks.dart"; | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Launch a dialog allowing the user to select from a list of options | ||||
|  */ | ||||
| Future<void> choiceDialog(String title, List<Widget> items, {Function? onSelected}) async { | ||||
|  | ||||
|   List<Widget> choices = []; | ||||
|  | ||||
|   for (int idx = 0; idx < items.length; idx++) { | ||||
|     choices.add( | ||||
|       GestureDetector( | ||||
|         child: items[idx], | ||||
|         onTap: () { | ||||
|           Navigator.pop(OneContext().context!); | ||||
|           if (onSelected != null) { | ||||
|             onSelected(idx); | ||||
|           } | ||||
|         }, | ||||
|       ) | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   OneContext().showDialog( | ||||
|     builder: (BuildContext context) { | ||||
|       return AlertDialog( | ||||
|         title: Text(title), | ||||
|         content: SingleChildScrollView( | ||||
|           child: Column( | ||||
|             children: choices, | ||||
|           ) | ||||
|         ), | ||||
|         actions: [ | ||||
|           TextButton( | ||||
|             child: Text(L10().cancel), | ||||
|             onPressed: () { | ||||
|               Navigator.pop(OneContext().context!); | ||||
|             }, | ||||
|           ) | ||||
|         ], | ||||
|       ); | ||||
|     } | ||||
|   ); | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Display a "confirmation" dialog allowing the user to accept or reject an action | ||||
|  */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user