diff --git a/.run/Sanmill-dev.run.xml b/.run/Sanmill-dev.run.xml new file mode 100644 index 00000000..c143d152 --- /dev/null +++ b/.run/Sanmill-dev.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.run/Sanmill-monkey.run.xml b/.run/Sanmill-monkey.run.xml new file mode 100644 index 00000000..d3f4b9a2 --- /dev/null +++ b/.run/Sanmill-monkey.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.run/Sanmill-profile.run.xml b/.run/Sanmill-profile.run.xml new file mode 100644 index 00000000..05d4dfd5 --- /dev/null +++ b/.run/Sanmill-profile.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.run/Sanmill-release.run.xml b/.run/Sanmill-release.run.xml new file mode 100644 index 00000000..983a17e1 --- /dev/null +++ b/.run/Sanmill-release.run.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.run/Sanmill.run.xml b/.run/Sanmill.run.xml new file mode 100644 index 00000000..c03f8656 --- /dev/null +++ b/.run/Sanmill.run.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.run/Template Flutter.run.xml b/.run/Template Flutter.run.xml new file mode 100644 index 00000000..f1bc2d08 --- /dev/null +++ b/.run/Template Flutter.run.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..84ad841a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,60 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Sanmill", + "type": "dart", + "request": "launch", + "cwd": "src/ui/flutter_app", + "program": "lib/main.dart" + }, + { + "name": "Sanmill: Attach to Device", + "type": "dart", + "request": "attach" + }, + { + "name": "Sanmill-dev", + "type": "dart", + "request": "launch", + "cwd": "src/ui/flutter_app", + "program": "lib/main.dart", + "args": [ + "--dart-define", + "dev_mode=true", + "--dart-define", + "catcher=false" + ] + }, + { + "name": "Sanmill-monkey", + "type": "dart", + "request": "launch", + "cwd": "src/ui/flutter_app", + "program": "lib/main.dart", + "args": [ + "--dart-define", + "monkey_test=true" + ] + }, + { + "name": "Sanmill-profile", + "type": "dart", + "request": "launch", + "cwd": "src/ui/flutter_app", + "program": "lib/main.dart", + "flutterMode": "profile" + }, + { + "name": "Sanmill-release", + "type": "dart", + "request": "launch", + "cwd": "src/ui/flutter_app", + "program": "lib/main.dart", + "flutterMode": "release" + } + ] +} \ No newline at end of file diff --git a/Readme.md b/Readme.md index 61c922ef..38f3cade 100644 --- a/Readme.md +++ b/Readme.md @@ -71,6 +71,21 @@ Use Qt Creator to open `millgame.pro` , or use Visual Studio to open `millgame.s Run `./flutter-init.sh` , copy `src/ui/flutter_app/android/key.properties.example` to `src/ui/flutter_app/android/key.properties`, modify it, and then use Android Studio or Visual Studio Code to open `src/ui/flutter_app` to build Flutter App. +We use compile time enviornmet configs to enable specific parts of the code: + +* `monkey_test` to prepare the app for monkey tests (references to external sites are going to be disabled) +* `dev_mode` to show the developer mode without needing to enable it first +* `catcher` to controll the use of catcher (this is on by default and needs to be disabled when needed) + +all enviornment configs can be combined and take a value of bool like: + +```shell +flutter run --dart-define catcher=false dev_mode=true +``` + +For ease of use some launch configs vor VS-Code and IntelliJ IDEA are available. Just select the +needed one in the `Run and Debug` or `Run/Debug Configurations` tab. + ## Understanding the code base and participating in the project Sanmill's improvement over the last couple of years has been a great community effort. There are a few ways to help contribute to its growth. diff --git a/src/ui/flutter_app/lib/main.dart b/src/ui/flutter_app/lib/main.dart index 6a999b5e..c3fa63cb 100644 --- a/src/ui/flutter_app/lib/main.dart +++ b/src/ui/flutter_app/lib/main.dart @@ -30,6 +30,7 @@ import 'package:sanmill/generated/intl/l10n.dart'; import 'package:sanmill/models/display.dart'; import 'package:sanmill/screens/navigation_home_screen.dart'; import 'package:sanmill/services/audios.dart'; +import 'package:sanmill/services/enviornment_config.dart'; import 'package:sanmill/services/language_info.dart'; import 'package:sanmill/services/storage/storage.dart'; import 'package:sanmill/services/storage/storage_v1.dart'; @@ -37,39 +38,30 @@ import 'package:sanmill/shared/constants.dart'; import 'package:sanmill/shared/theme/app_theme.dart'; part 'package:sanmill/services/catcher.dart'; +part 'package:sanmill/services/init_system_ui.dart'; Future main() async { + debugPrint('Enviornment [catcher]: ${EnvironmentConfig.catcher}'); + debugPrint('Enviornment [dev_mode]: ${EnvironmentConfig.devMode}'); + debugPrint('Enviornment [monkey_test]: ${EnvironmentConfig.monkeyTest}'); + await LocalDatabaseService.initStorage(); await DatabaseV1.migrateDB(); - final catcher = Catcher( - rootWidget: const BetterFeedback( - child: SanmillApp(), - //localeOverride: Locale(Resources.of().languageCode), - ), - ensureInitialized: true, - ); - await _initCatcher(catcher); + _initUI(); - debugPrint(window.physicalSize.toString()); - debugPrint(Constants.windowAspectRatio.toString()); - - SystemChrome.setPreferredOrientations( - [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown], - ); - - if (Platform.isAndroid && isLargeScreen) { - SystemChrome.setSystemUIOverlayStyle( - const SystemUiOverlayStyle( - statusBarColor: Colors.transparent, - statusBarBrightness: Brightness.light, - statusBarIconBrightness: Brightness.dark, - systemNavigationBarColor: Colors.black, - systemNavigationBarIconBrightness: Brightness.dark, + if (EnvironmentConfig.catcher) { + final catcher = Catcher( + rootWidget: const BetterFeedback( + child: SanmillApp(), + //localeOverride: Locale(Resources.of().languageCode), ), + ensureInitialized: true, ); - } else if (isSmallScreen) { - SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); + + await _initCatcher(catcher); + } else { + runApp(const SanmillApp()); } } @@ -83,8 +75,6 @@ class SanmillApp extends StatelessWidget { final globalScaffoldKey = GlobalKey(); Audios.loadSounds(); - setSpecialCountryAndRegion(context); - return ValueListenableBuilder( valueListenable: LocalDatabaseService.listenDisplay, builder: (BuildContext context, Box displayBox, _) { @@ -95,7 +85,7 @@ class SanmillApp extends StatelessWidget { return MaterialApp( /// Add navigator key from Catcher. /// It will be used to navigate user to report page or to show dialog. - navigatorKey: Catcher.navigatorKey, + navigatorKey: EnvironmentConfig.catcher ? Catcher.navigatorKey : null, key: globalScaffoldKey, navigatorObservers: [routeObserver], localizationsDelegates: S.localizationsDelegates, @@ -104,25 +94,22 @@ class SanmillApp extends StatelessWidget { theme: AppTheme.lightThemeData, darkTheme: AppTheme.darkThemeData, debugShowCheckedModeBanner: false, - home: const _Home(), + home: Builder( + builder: (context) { + setSpecialCountryAndRegion(context); + + return Scaffold( + body: DoubleBackToCloseApp( + snackBar: SnackBar( + content: Text(S.of(context).tapBackAgainToLeave), + ), + child: const NavigationHomeScreen(), + ), + ); + }, + ), ); }, ); } } - -class _Home extends StatelessWidget { - const _Home({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: DoubleBackToCloseApp( - snackBar: SnackBar( - content: Text(S.of(context).tapBackAgainToLeave), - ), - child: const NavigationHomeScreen(), - ), - ); - } -} diff --git a/src/ui/flutter_app/lib/models/temporary.dart b/src/ui/flutter_app/lib/models/temporary.dart index 077f46e8..f19cb797 100644 --- a/src/ui/flutter_app/lib/models/temporary.dart +++ b/src/ui/flutter_app/lib/models/temporary.dart @@ -16,6 +16,8 @@ along with this program. If not, see . */ +import 'package:sanmill/services/enviornment_config.dart'; + /// Temporary data model /// /// holds temporary runtime data that isn't yet or shouldn't be saved to the LocalDatabase @@ -23,5 +25,5 @@ class Temp { const Temp._(); /// represents a temporary value for Preferences.developerMode - static bool developerMode = false; + static bool developerMode = EnvironmentConfig.devMode; } diff --git a/src/ui/flutter_app/lib/screens/game_settings/game_settings_page.dart b/src/ui/flutter_app/lib/screens/game_settings/game_settings_page.dart index 36ec8bbc..01174d9b 100644 --- a/src/ui/flutter_app/lib/screens/game_settings/game_settings_page.dart +++ b/src/ui/flutter_app/lib/screens/game_settings/game_settings_page.dart @@ -25,6 +25,7 @@ import 'package:sanmill/generated/intl/l10n.dart'; import 'package:sanmill/models/preferences.dart'; import 'package:sanmill/models/temporary.dart'; import 'package:sanmill/screens/env_page.dart'; +import 'package:sanmill/services/enviornment_config.dart'; import 'package:sanmill/services/storage/storage.dart'; import 'package:sanmill/shared/settings/settings_card.dart'; import 'package:sanmill/shared/settings/settings_list_tile.dart'; diff --git a/src/ui/flutter_app/lib/screens/game_settings/reset_settings_alert.dart b/src/ui/flutter_app/lib/screens/game_settings/reset_settings_alert.dart index 63dcd7e7..3261c561 100644 --- a/src/ui/flutter_app/lib/screens/game_settings/reset_settings_alert.dart +++ b/src/ui/flutter_app/lib/screens/game_settings/reset_settings_alert.dart @@ -25,7 +25,10 @@ class _ResetSettingsAlert extends StatelessWidget { Future _restore(BuildContext context) async { Navigator.pop(context); - if (!LocalDatabaseService.preferences.developerMode) { + + // TODO: we should probably enable database deletion in monkey tests + //as the new storage backend supports deletion without needing an app restart + if (!EnvironmentConfig.monkeyTest) { await LocalDatabaseService.resetStorage(); } } diff --git a/src/ui/flutter_app/lib/screens/navigation_home_screen.dart b/src/ui/flutter_app/lib/screens/navigation_home_screen.dart index 7a1b1291..20aef7d4 100644 --- a/src/ui/flutter_app/lib/screens/navigation_home_screen.dart +++ b/src/ui/flutter_app/lib/screens/navigation_home_screen.dart @@ -36,6 +36,7 @@ import 'package:sanmill/screens/help_screen.dart'; import 'package:sanmill/screens/personalization_settings/personalization_settings_page.dart'; import 'package:sanmill/screens/rule_settings/rule_settings_page.dart'; import 'package:sanmill/services/engine/engine.dart'; +import 'package:sanmill/services/enviornment_config.dart'; import 'package:sanmill/services/storage/storage.dart'; import 'package:sanmill/shared/constants.dart'; import 'package:sanmill/shared/theme/app_theme.dart'; @@ -103,7 +104,7 @@ class _NavigationHomeScreenState extends State { } else if (drawerIndex == DrawerIndex.personalization) { screenView = PersonalizationSettingsPage(); } else if (drawerIndex == DrawerIndex.feedback && - !LocalDatabaseService.preferences.developerMode) { + !EnvironmentConfig.monkeyTest) { if (Platform.isWindows) { debugPrint("flutter_email_sender does not support Windows."); //_launchFeedback(); @@ -128,10 +129,10 @@ class _NavigationHomeScreenState extends State { }); } } else if (drawerIndex == DrawerIndex.Help && - !LocalDatabaseService.preferences.developerMode) { + !EnvironmentConfig.monkeyTest) { screenView = HelpScreen(); } else if (drawerIndex == DrawerIndex.About && - !LocalDatabaseService.preferences.developerMode) { + !EnvironmentConfig.monkeyTest) { screenView = AboutPage(); } else { //do in your way...... diff --git a/src/ui/flutter_app/lib/services/enviornment_config.dart b/src/ui/flutter_app/lib/services/enviornment_config.dart new file mode 100644 index 00000000..68afbef9 --- /dev/null +++ b/src/ui/flutter_app/lib/services/enviornment_config.dart @@ -0,0 +1,34 @@ +/* + This file is part of Sanmill. + Copyright (C) 2019-2021 The Sanmill developers (see AUTHORS file) + + Sanmill is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Sanmill is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/// Enviornment configutation +/// +/// Enables devs to start the app with compile time options +class EnvironmentConfig { + const EnvironmentConfig._(); + + /// gets weather we build for a monkey test + static const monkeyTest = bool.fromEnvironment('monkey_test'); + + /// gets weather we build for devMode + static const devMode = bool.fromEnvironment('dev_mode'); + + /// gets weather we want catcher to be enabled + /// defaults to true + static const catcher = bool.fromEnvironment('catcher', defaultValue: true); +} diff --git a/src/ui/flutter_app/lib/services/init_system_ui.dart b/src/ui/flutter_app/lib/services/init_system_ui.dart new file mode 100644 index 00000000..6b7e52ad --- /dev/null +++ b/src/ui/flutter_app/lib/services/init_system_ui.dart @@ -0,0 +1,43 @@ +/* + This file is part of Sanmill. + Copyright (C) 2019-2021 The Sanmill developers (see AUTHORS file) + + Sanmill is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Sanmill is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +part of 'package:sanmill/main.dart'; + +/// initializes the given [SystemChrome] ui +void _initUI() { + debugPrint(window.physicalSize.toString()); + debugPrint(Constants.windowAspectRatio.toString()); + + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown], + ); + + if (Platform.isAndroid && isLargeScreen) { + SystemChrome.setSystemUIOverlayStyle( + const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + statusBarBrightness: Brightness.light, + statusBarIconBrightness: Brightness.dark, + systemNavigationBarColor: Colors.black, + systemNavigationBarIconBrightness: Brightness.dark, + ), + ); + } else if (isSmallScreen) { + SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); + } +}