├── .github └── FUNDING.yml ├── .gitignore ├── .idea └── .gitignore ├── .travis.yml ├── .vscode └── launch.json ├── LICENSE ├── README.md ├── gic_flutter ├── .gitignore ├── .metadata ├── .run │ └── Flutter Dev.run.xml ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── .project │ ├── app │ │ ├── .project │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ ├── src │ │ │ ├── debug │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── res │ │ │ │ │ └── values │ │ │ │ │ └── strings.xml │ │ │ ├── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── ic_launcher-web.png │ │ │ │ ├── kotlin │ │ │ │ │ └── ca │ │ │ │ │ │ └── coffeeshopstudio │ │ │ │ │ │ └── gaminginterfaceclient │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── res │ │ │ │ │ ├── drawable │ │ │ │ │ ├── ic_arrow_back_white_24dp.xml │ │ │ │ │ ├── launch_background.xml │ │ │ │ │ └── launch_image.png │ │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ │ └── ic_launcher.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── values-sw720dp │ │ │ │ │ └── dimens.xml │ │ │ │ │ ├── values-v21 │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values │ │ │ │ │ ├── attrs.xml │ │ │ │ │ ├── colors.xml │ │ │ │ │ ├── dimens.xml │ │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── web_hi_res_512.png │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ ├── audio │ │ └── flick.wav │ ├── fonts │ │ ├── Lobster-Regular.ttf │ │ ├── Nunito-Regular.ttf │ │ ├── OFL.txt │ │ ├── Righteous-Regular.ttf │ │ └── ShareTech-Regular.ttf │ ├── images │ │ ├── controls │ │ │ ├── button_black.png │ │ │ ├── button_black2.png │ │ │ ├── button_black2_dark.png │ │ │ ├── button_black_dark.png │ │ │ ├── button_blue.png │ │ │ ├── button_blue2.png │ │ │ ├── button_blue2_dark.png │ │ │ ├── button_blue_dark.png │ │ │ ├── button_green.png │ │ │ ├── button_green2.png │ │ │ ├── button_green2_dark.png │ │ │ ├── button_green_dark.png │ │ │ ├── button_grey.png │ │ │ ├── button_grey2.png │ │ │ ├── button_grey2_dark.png │ │ │ ├── button_grey_dark.png │ │ │ ├── button_neon.png │ │ │ ├── button_neon_dark.png │ │ │ ├── button_purple.png │ │ │ ├── button_purple_dark.png │ │ │ ├── button_red.png │ │ │ ├── button_red2.png │ │ │ ├── button_red2_dark.png │ │ │ ├── button_red_dark.png │ │ │ ├── button_toggle_off.png │ │ │ ├── button_toggle_on.png │ │ │ ├── button_white.png │ │ │ ├── button_white_dark.png │ │ │ ├── button_yellow.png │ │ │ ├── button_yellow_dark.png │ │ │ ├── lever_off.png │ │ │ ├── lever_on.png │ │ │ ├── switch_off.png │ │ │ ├── switch_on.png │ │ │ ├── toggle_off.png │ │ │ └── toggle_on.png │ │ └── icons │ │ │ └── app_icon.png │ └── screens │ │ ├── Elite-LargeTablet.json │ │ ├── Elite-Phone.json │ │ ├── Elite-SmallTablet.json │ │ ├── SC-LargeTablet.json │ │ ├── SC-Phone.json │ │ └── SC-SmallTablet.json ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h ├── lib │ └── src │ │ ├── app.dart │ │ ├── backend │ │ ├── blocs │ │ │ ├── launcherBloc.dart │ │ │ └── newScreenWizardBloc.dart │ │ ├── models │ │ │ ├── autoItKeyMap.dart │ │ │ ├── channel.dart │ │ │ ├── intl │ │ │ │ ├── intlAbout.dart │ │ │ │ ├── intlFeedback.dart │ │ │ │ ├── intlLauncher.dart │ │ │ │ ├── intlNewScreenWizard.dart │ │ │ │ ├── intlOptions.dart │ │ │ │ ├── intlScreenEditor.dart │ │ │ │ └── localizations.dart │ │ │ ├── launcherModel.dart │ │ │ ├── networkModel.dart │ │ │ ├── newScreenWizardModel.dart │ │ │ ├── screen │ │ │ │ ├── command.dart │ │ │ │ ├── controlDefaults.dart │ │ │ │ ├── controlTypes.dart │ │ │ │ ├── fonts.dart │ │ │ │ ├── gicControl.dart │ │ │ │ ├── screen.dart │ │ │ │ └── viewModels │ │ │ │ │ ├── controlViewModel.dart │ │ │ │ │ ├── drawable.dart │ │ │ │ │ ├── font.dart │ │ │ │ │ └── screenViewModel.dart │ │ │ ├── viewModel.dart │ │ │ └── viewSection.dart │ │ ├── repositories │ │ │ ├── launcherRepository.dart │ │ │ └── screenRepository.dart │ │ └── services │ │ │ ├── compressedFileService.dart │ │ │ ├── cryptoService.dart │ │ │ ├── firstRunService.dart │ │ │ ├── networkService.dart │ │ │ ├── screenImportService.dart │ │ │ └── screenService.dart │ │ ├── flavor.dart │ │ ├── main_gplay.dart │ │ ├── main_other.dart │ │ ├── service_locator.dart │ │ ├── theme │ │ ├── dimensions.dart │ │ ├── style.dart │ │ └── theme.dart │ │ └── views │ │ ├── about │ │ ├── aboutPresentation.dart │ │ ├── aboutVM.dart │ │ └── aboutView.dart │ │ ├── accentButton.dart │ │ ├── baseGicControl.dart │ │ ├── basePage.dart │ │ ├── feedback │ │ ├── feedbackPresentation.dart │ │ ├── feedbackVM.dart │ │ └── feedbackView.dart │ │ ├── intro │ │ ├── introPresentation.dart │ │ ├── introView.dart │ │ ├── screenListWidget.dart │ │ └── screenSizeWidget.dart │ │ ├── launcher │ │ ├── launcher.dart │ │ ├── screenList.dart │ │ └── serverLogin.dart │ │ ├── menuOption.dart │ │ ├── newScreenWizard │ │ ├── controlDesignWidget.dart │ │ ├── layoutWidget.dart │ │ ├── newScreenWizard.dart │ │ ├── newScreenWizardControls.dart │ │ ├── newScreenWizardGeneral.dart │ │ └── orientationWidget.dart │ │ ├── options │ │ ├── optionsPresentation.dart │ │ ├── optionsVM.dart │ │ └── optionsView.dart │ │ ├── screen │ │ ├── gicControl.dart │ │ ├── screenVM.dart │ │ └── screenView.dart │ │ └── screenEditor │ │ ├── backgroundDialog.dart │ │ ├── colorPickerDialog.dart │ │ ├── controlDialog │ │ ├── baseTab.dart │ │ ├── commandTab.dart │ │ ├── controlDialog.dart │ │ ├── designTab.dart │ │ ├── imageDialog.dart │ │ ├── sizeTab.dart │ │ └── textTab.dart │ │ ├── gicEditControl.dart │ │ ├── helpDialog │ │ ├── helpDialog.dart │ │ └── selectTab.dart │ │ ├── screenEditor.dart │ │ └── settingsDialog │ │ ├── dialogButton.dart │ │ ├── dialogSlider.dart │ │ └── settingsDialog.dart ├── pubspec.lock ├── pubspec.yaml ├── runbuild.sh └── runbuild.win.sh ├── release_notes.txt └── xgesture_flutter ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── lib └── gesture_x_detector.dart ├── pubspec.lock ├── pubspec.yaml └── test └── gesture_x_detector_test.dart /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | #github: # 4 | patreon: coffeeshopstudio 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/modules.xml 2 | /.idea/navEditor.xml 3 | .DS_Store 4 | 5 | # Built application files 6 | *.apk 7 | *.ap_ 8 | *.aab 9 | 10 | # Files for the ART/Dalvik VM 11 | *.dex 12 | 13 | # Java class files 14 | *.class 15 | 16 | # Generated files 17 | bin/ 18 | gen/ 19 | out/ 20 | 21 | # Gradle files 22 | .gradle/ 23 | build/ 24 | 25 | # Local configuration file (sdk path, etc) 26 | local.properties 27 | 28 | # Proguard folder generated by Eclipse 29 | proguard/ 30 | 31 | # Log Files 32 | *.log 33 | 34 | # Android Studio Navigation editor temp files 35 | .navigation/ 36 | 37 | # Android Studio captures folder 38 | captures/ 39 | 40 | # IntelliJ 41 | *.iml 42 | .idea/workspace.xml 43 | .idea/tasks.xml 44 | .idea/gradle.xml 45 | .idea/assetWizardSettings.xml 46 | .idea/dictionaries 47 | .idea/libraries 48 | .idea/caches 49 | 50 | # Keystore files 51 | # Uncomment the following lines if you do not want to check your keystore files in. 52 | *.jks 53 | *.keystore 54 | 55 | # External native build folder generated in Android Studio 2.2 and later 56 | .externalNativeBuild 57 | 58 | # Google Services (e.g. APIs or Firebase) 59 | # google-services.json 60 | 61 | # Freeline 62 | freeline.py 63 | freeline/ 64 | freeline_project_description.json 65 | 66 | # fastlane 67 | fastlane/report.xml 68 | fastlane/Preview.html 69 | fastlane/screenshots 70 | fastlane/test_output 71 | fastlane/readme.md 72 | 73 | # Version control 74 | vcs.xml 75 | 76 | # lint 77 | lint/intermediates/ 78 | lint/generated/ 79 | lint/outputs/ 80 | lint/tmp/ 81 | # lint/reports/ 82 | 83 | gic_android/.idea/caches/ 84 | gic_android/.idea/gradle.xml 85 | gic_android/.idea/libraries/ 86 | gic_android/.idea/modules.xml 87 | gic_android/.idea/workspace.xml 88 | gic_flutter/android/key.properties 89 | gic_flutter/ios/Flutter/flutter_export_environment.sh 90 | gic_flutter/android/.settings/org.eclipse.buildship.core.prefs 91 | gic_flutter/android/app/.classpath 92 | gic_flutter/android/app/.settings/org.eclipse.buildship.core.prefs 93 | .idea/encodings.xml 94 | .idea/misc.xml 95 | .idea/codeStyles/Project.xml 96 | gic_flutter/.flutter-plugins-dependencies 97 | /xgesture_flutter/.dart_tool/package_config.json 98 | /xgesture_flutter/.dart_tool/package_config_subset 99 | /xgesture_flutter/.dart_tool/version 100 | /xgesture_flutter/.dart_tool/extension_discovery/vs_code.json 101 | /.idea/other.xml 102 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - linux 3 | sudo: false 4 | addons: 5 | apt: 6 | sources: 7 | - ubuntu-toolchain-r-test 8 | packages: 9 | - libstdc++6 10 | - fonts-noto 11 | git: 12 | depth: 3 13 | env: 14 | - FLUTTER_VERSION=stable 15 | - FLUTTER_VERSION=beta 16 | matrix: 17 | allow_failures: 18 | - env: FLUTTER_VERSION=beta 19 | before_script: 20 | - git clone https://github.com/flutter/flutter.git -b $FLUTTER_VERSION 21 | - ./flutter/bin/flutter doctor 22 | - chmod +x travis_script.sh 23 | script: 24 | - ./travis_script.sh 25 | cache: 26 | directories: 27 | - $HOME/shared/.pub-cache 28 | # notifications: 29 | # email: 30 | # brogdon+github@gmail.com 31 | 32 | # Only building master means that we don't run two builds for each pull request. 33 | branches: 34 | only: [master] 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | # language: generic 48 | # dist: xenial 49 | # addons: 50 | # apt: 51 | # packages: 52 | # - lib32stdc++6 53 | # env: 54 | # global: 55 | # - FLUTTER_CHANNEL=stable 56 | # before_install: 57 | # cd gic_flutter 58 | # install: 59 | # - git clone https://github.com/flutter/flutter.git -b $FLUTTER_CHANNEL 60 | # - export PATH="$PATH:`pwd`/flutter/bin/cache/dart-sdk/bin" 61 | # - export PATH="$PATH:`pwd`/flutter/bin" 62 | # - flutter doctor -v 63 | # - flutter packages get 64 | # cache: 65 | # directories: 66 | # - $HOME/.pub-cache 67 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Flutter Other", 9 | "program": "gic_flutter/lib/main_other.dart", 10 | "request": "launch", 11 | "type": "dart", 12 | "args": [ 13 | "--flavor", 14 | "other" 15 | ] 16 | }, 17 | { 18 | "name": "Flutter GPlay", 19 | "program": "gic_flutter/lib/main_gplay.dart", 20 | "request": "launch", 21 | "type": "dart", 22 | "args": [ 23 | "--flavor", 24 | "gplay" 25 | ] 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Codemagic build status](https://api.codemagic.io/apps/5df31599c3cc4f70a402350d/6501db48531b66edd968d29a/status_badge.svg)](https://codemagic.io/apps/5df31599c3cc4f70a402350d/6501db48531b66edd968d29a/latest_build) 2 | # Gaming Interface Client (Android) 3 | 4 | Android client for the Gaming Interface Client 5 | 6 | **Download Android Files Here https://github.com/Terence-D/GamingInterfaceClientAndroid/releases** 7 | 8 | This is part of a two app system that allows the use of a remote device (Tablet or Phone) to provide input into a PC game or application. This software is the Android Client and runs on your Tablet or Phone. It talks to the GICServer - https://github.com/Terence-D/GameInputCommandServer For example if you play a space simulator, you can add custom buttons for Comms, Warp Drive, Power control, etc and have it accessible at your fingertips without remembering complex keystrokes. 9 | 10 | ## Features 11 | * Open Source and Free! 12 | * Completely customizable - build the layout YOU want 13 | * Supports multiple devices connecting to the server. Use one Tablet for your ship Systems, another for Comms! 14 | * Runs on Phones or Tablets 15 | * Supports practically any game 16 | * More features to be worked on! 17 | 18 | Check the Wiki here https://github.com/Terence-D/GamingInterfaceClientAndroid/wiki for more information. Any issues please add to the Issue tracker, or contact me at support [ a]t coffeeshopstudio.ca 19 | 20 | ## Help 21 | Help with testing or donations is always appreciated, donation links are on the right hand side! 22 | 23 | ## New Planned Features 24 | iOS and more! https://github.com/Terence-D/GamingInterfaceClientAndroid/labels/enhancement 25 | -------------------------------------------------------------------------------- /gic_flutter/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .packages 26 | .pub-cache/ 27 | .pub/ 28 | /build/ 29 | 30 | # Android related 31 | **/android/**/gradle-wrapper.jar 32 | **/android/.gradle 33 | **/android/captures/ 34 | **/android/gradlew 35 | **/android/gradlew.bat 36 | **/android/local.properties 37 | **/android/**/GeneratedPluginRegistrant.java 38 | 39 | # iOS/XCode related 40 | **/ios/**/*.mode1v3 41 | **/ios/**/*.mode2v3 42 | **/ios/**/*.moved-aside 43 | **/ios/**/*.pbxuser 44 | **/ios/**/*.perspectivev3 45 | **/ios/**/*sync/ 46 | **/ios/**/.sconsign.dblite 47 | **/ios/**/.tags* 48 | **/ios/**/.vagrant/ 49 | **/ios/**/DerivedData/ 50 | **/ios/**/Icon? 51 | **/ios/**/Pods/ 52 | **/ios/**/.symlinks/ 53 | **/ios/**/profile 54 | **/ios/**/xcuserdata 55 | **/ios/.generated/ 56 | **/ios/Flutter/App.framework 57 | **/ios/Flutter/Flutter.framework 58 | **/ios/Flutter/Generated.xcconfig 59 | **/ios/Flutter/app.flx 60 | **/ios/Flutter/app.zip 61 | **/ios/Flutter/flutter_assets/ 62 | **/ios/ServiceDefinitions.json 63 | **/ios/Runner/GeneratedPluginRegistrant.* 64 | 65 | # Exceptions to above rules. 66 | !**/ios/**/default.mode1v3 67 | !**/ios/**/default.mode2v3 68 | !**/ios/**/default.pbxuser 69 | !**/ios/**/default.perspectivev3 70 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 71 | /android/settings_aar.gradle 72 | android/key.properties -------------------------------------------------------------------------------- /gic_flutter/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /gic_flutter/.run/Flutter Dev.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /gic_flutter/README.md: -------------------------------------------------------------------------------- 1 | # gic_flutter 2 | 3 | Gaming Interface Client 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /gic_flutter/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:pedantic/analysis_options.1.8.0.yaml 2 | 3 | linter: 4 | rules: 5 | - unawaited_futures -------------------------------------------------------------------------------- /gic_flutter/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /gic_flutter/android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /gic_flutter/android/app/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | app 4 | Project app created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /gic_flutter/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new Exception("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | def keystoreProperties = new Properties() 25 | def keystorePropertiesFile = rootProject.file('key.properties') 26 | if (keystorePropertiesFile.exists()) { 27 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 28 | } 29 | 30 | apply plugin: 'com.android.application' 31 | apply plugin: 'kotlin-android' 32 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 33 | 34 | android { 35 | flavorDimensions "version" 36 | compileSdk = flutter.compileSdkVersion 37 | 38 | sourceSets { 39 | main.java.srcDirs += 'src/main/kotlin' 40 | } 41 | 42 | lintOptions { 43 | disable 'InvalidPackage' 44 | checkReleaseBuilds false 45 | } 46 | 47 | defaultConfig { 48 | applicationId "ca.coffeeshopstudio.gaminginterfaceclient" 49 | minSdk = flutter.minSdkVersion 50 | targetSdk = 35 //flutter.targetSdkVersion 51 | versionCode flutterVersionCode.toInteger() 52 | versionName flutterVersionName 53 | multiDexEnabled true 54 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 55 | } 56 | 57 | productFlavors { 58 | gplay { 59 | } 60 | 61 | other { 62 | applicationId "ca.coffeeshopstudio.gaminginterfaceclient.internal" 63 | } 64 | } 65 | 66 | signingConfigs { 67 | release { 68 | keyAlias keystoreProperties['keyAlias'] 69 | keyPassword keystoreProperties['keyPassword'] 70 | storeFile file(keystoreProperties['storeFile']) 71 | storePassword keystoreProperties['storePassword'] 72 | } 73 | debug {} 74 | } 75 | 76 | buildTypes { 77 | release { 78 | signingConfig signingConfigs.release 79 | minifyEnabled false 80 | shrinkResources false 81 | //useProguard true 82 | //proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 83 | } 84 | debug { 85 | signingConfig signingConfigs.debug 86 | } 87 | } 88 | } 89 | 90 | flutter { 91 | source '../..' 92 | } 93 | 94 | dependencies { 95 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20" 96 | } 97 | -------------------------------------------------------------------------------- /gic_flutter/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | ## Flutter wrapper 24 | -keep class io.flutter.app.** { *; } 25 | -keep class io.flutter.plugin.** { *; } 26 | -keep class io.flutter.util.** { *; } 27 | -keep class io.flutter.view.** { *; } 28 | -keep class io.flutter.** { *; } 29 | -keep class io.flutter.plugins.** { *; } -------------------------------------------------------------------------------- /gic_flutter/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/debug/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | GIC-Int 3 | 4 | GIC-Int 5 | 6 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 | 34 | 35 | 36 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/kotlin/ca/coffeeshopstudio/gaminginterfaceclient/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package ca.coffeeshopstudio.gaminginterfaceclient 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | class MainActivity: FlutterActivity() { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/drawable/ic_arrow_back_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/drawable/launch_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/src/main/res/drawable/launch_image.png -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/values-sw720dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 32dp 4 | 64dp 5 | 64dp 6 | 64sp 7 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #2A41B3 5 | #43a047 6 | #F44336 7 | 8 | #66000000 9 | #FF383838 10 | #A1F8F8F8 11 | 12 | #33343B 13 | #8033343B 14 | #33343B 15 | 16 | #5160B6 17 | 18 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 16dp 6 | 16dp 7 | 32sp 8 | 320dp 9 | 92dp 10 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #4C5DBA 4 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Gaming Interface Client 3 | 4 | Gaming Interface Client 5 | 6 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 13 | 14 | 15 | 21 | 22 | 29 | 30 | 33 | 34 | 40 | 41 | 53 | 54 | 58 | 59 | 62 | 63 | -------------------------------------------------------------------------------- /gic_flutter/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gic_flutter/android/app/web_hi_res_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/android/app/web_hi_res_512.png -------------------------------------------------------------------------------- /gic_flutter/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:7.3.1' 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.20" 10 | } 11 | } 12 | 13 | allprojects { 14 | repositories { 15 | google() 16 | mavenCentral() 17 | maven { url 'https://jitpack.io' } 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | tasks.register("clean", Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /gic_flutter/android/gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableJetifier=true 2 | android.useAndroidX=true 3 | org.gradle.jvmargs=-Xmx1024M 4 | android.enableR8=true 5 | -------------------------------------------------------------------------------- /gic_flutter/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 07 16:27:57 MST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip 7 | -------------------------------------------------------------------------------- /gic_flutter/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /gic_flutter/assets/audio/flick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/audio/flick.wav -------------------------------------------------------------------------------- /gic_flutter/assets/fonts/Lobster-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/fonts/Lobster-Regular.ttf -------------------------------------------------------------------------------- /gic_flutter/assets/fonts/Nunito-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/fonts/Nunito-Regular.ttf -------------------------------------------------------------------------------- /gic_flutter/assets/fonts/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright 2010 The Lobster Project Authors (https://github.com/impallari/The-Lobster-Font), with Reserved Font Name "Lobster". 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /gic_flutter/assets/fonts/Righteous-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/fonts/Righteous-Regular.ttf -------------------------------------------------------------------------------- /gic_flutter/assets/fonts/ShareTech-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/fonts/ShareTech-Regular.ttf -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_black.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_black2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_black2.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_black2_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_black2_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_black_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_black_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_blue.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_blue2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_blue2.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_blue2_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_blue2_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_blue_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_blue_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_green.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_green2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_green2.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_green2_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_green2_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_green_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_green_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_grey.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_grey2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_grey2.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_grey2_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_grey2_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_grey_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_grey_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_neon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_neon.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_neon_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_neon_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_purple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_purple.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_purple_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_purple_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_red.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_red2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_red2.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_red2_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_red2_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_red_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_red_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_toggle_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_toggle_off.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_toggle_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_toggle_on.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_white.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_white_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_white_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_yellow.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/button_yellow_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/button_yellow_dark.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/lever_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/lever_off.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/lever_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/lever_on.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/switch_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/switch_off.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/switch_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/switch_on.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/toggle_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/toggle_off.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/controls/toggle_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/controls/toggle_on.png -------------------------------------------------------------------------------- /gic_flutter/assets/images/icons/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/assets/images/icons/app_icon.png -------------------------------------------------------------------------------- /gic_flutter/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /gic_flutter/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /gic_flutter/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /gic_flutter/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Terence-D/GamingInterfaceClientAndroid/f71658c54f0c485e5c2791674ea53c2e271af6e3/gic_flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | gic_flutter 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /gic_flutter/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_localizations/flutter_localizations.dart'; 3 | import 'package:gic_flutter/src/views/intro/introView.dart'; 4 | import 'package:gic_flutter/src/views/launcher/launcher.dart'; 5 | import 'backend/models/intl/localizations.dart'; 6 | import 'backend/services/firstRunService.dart'; 7 | import 'service_locator.dart'; 8 | import 'theme/theme.dart'; 9 | 10 | class GicApp extends StatelessWidget { 11 | GicApp (); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return MaterialApp( 16 | onGenerateTitle: (BuildContext context) => Intl.of(context)!.title, 17 | theme: MyAppThemes.lightTheme, 18 | darkTheme: MyAppThemes.darkTheme, 19 | themeMode: ThemeMode.system, 20 | home: _getStartupScreen(), 21 | localizationsDelegates: [ 22 | const IntlDelegate(), 23 | GlobalMaterialLocalizations.delegate, 24 | GlobalWidgetsLocalizations.delegate, 25 | ], 26 | supportedLocales: [ 27 | const Locale('en', ''), 28 | ], 29 | ); 30 | } 31 | 32 | Widget _getStartupScreen() { 33 | var localStorageService = locator(); 34 | if(localStorageService.firstRun) { 35 | return IntroView(); 36 | } 37 | return Launcher(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/blocs/launcherBloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:gic_flutter/src/backend/models/launcherModel.dart'; 5 | import 'package:gic_flutter/src/backend/models/networkModel.dart'; 6 | import 'package:gic_flutter/src/backend/models/screen/viewModels/screenViewModel.dart'; 7 | import 'package:gic_flutter/src/backend/repositories/launcherRepository.dart'; 8 | import 'package:rxdart/rxdart.dart'; 9 | 10 | /// LauncherBloc acts as the Presentation layer for the Launcher UI 11 | class LauncherBloc { 12 | LauncherRepository? _repository; 13 | PublishSubject? _modelFetcher; 14 | LauncherModel? itemModel; 15 | 16 | LauncherBloc() { 17 | this._repository = LauncherRepository(); 18 | this._modelFetcher = PublishSubject(); 19 | } 20 | 21 | LauncherBloc.withMocks(repository) { 22 | _repository = repository; 23 | this._modelFetcher = PublishSubject(); 24 | } 25 | 26 | Stream get preferences => _modelFetcher!.stream; 27 | 28 | /// Loads the preferences from the repository, and adds to the sink 29 | Future fetchAllPreferences() async { 30 | itemModel = await _repository!.fetch(); 31 | _modelFetcher?.sink.add(itemModel); 32 | } 33 | 34 | /// saves the server connection settings 35 | /// 36 | /// @param address Address for the GIC server 37 | /// @param port Port number of the GIC server 38 | /// @param password Secret for securing the connection to the GIC server 39 | void saveConnectionSettings(NetworkModel networkModel) { 40 | _repository?.saveMainSettings(networkModel); 41 | } 42 | 43 | /// Sets the purchase value 44 | void setDonation(String id, bool newValue) { 45 | _repository?.setDonation(id, newValue); 46 | } 47 | 48 | /// closes the stream 49 | void dispose() { 50 | _modelFetcher?.close(); 51 | } 52 | 53 | /// Changes the screen name 54 | /// 55 | /// @param id Id of the screen we want to update the name of 56 | /// @param newName New name of the screen 57 | Future updateScreenName(int? id, String? newName) async { 58 | await _repository?.updateName(id, newName); 59 | } 60 | 61 | /// Deletes the screen 62 | /// 63 | /// @param id The Id of the screen we want to remove 64 | /// @return The new cache size, or -1 if an error occurs 65 | Future deleteScreen(int? id) async { 66 | int? rv = await _repository?.deleteScreen(id); 67 | 68 | if (rv! >= 0) { 69 | await fetchAllPreferences(); 70 | } 71 | 72 | return rv; 73 | } 74 | 75 | /// Imports a new screen into GIC 76 | /// 77 | /// @param file the file we are importing 78 | /// @return the new Id of the imported screen, or a negative value on failure 79 | Future import(String file) async { 80 | int newItemId = await _repository!.import(file); 81 | await fetchAllPreferences(); 82 | 83 | return newItemId; 84 | } 85 | 86 | /// Exports a new screen into GIC 87 | /// 88 | /// @param exportPath directory we are exporting to 89 | /// @param id Id of the screen we want to export 90 | /// @return complete path of file 91 | Future export(String? exportPath, int? id) async { 92 | return await _repository!.export(exportPath, id); 93 | } 94 | 95 | Future checkScreenSize(int screenId) async { 96 | return await _repository!.checkScreenSize(screenId); 97 | } 98 | 99 | List getDimensions(BuildContext context) { 100 | return _repository!.buildDimensions(context); 101 | } 102 | 103 | bool getSound() { 104 | return itemModel!.sound; 105 | } 106 | 107 | bool getVibration() { 108 | return itemModel!.vibration; 109 | } 110 | 111 | bool getKeepScreenOn() => itemModel!.keepScreenOn; 112 | 113 | /// and resizes the screen to fit the devices dimensions 114 | /// saved as a new screen 115 | void resize(int screenId, BuildContext context) async { 116 | await _repository!.resizeScreen(screenId, context); 117 | await fetchAllPreferences(); 118 | } 119 | 120 | Future loadScreen(int screenId) async { 121 | return await _repository!.setActiveScreen(screenId); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/blocs/newScreenWizardBloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/backend/models/newScreenWizardModel.dart'; 3 | import 'package:gic_flutter/src/backend/models/screen/command.dart'; 4 | import 'package:gic_flutter/src/backend/models/screen/viewModels/controlViewModel.dart'; 5 | import 'package:gic_flutter/src/backend/services/screenService.dart'; 6 | 7 | /// This is the presentation layer of the new screen wizard ui 8 | /// It's pretty simplistic, and doesn't need a lot of bloc fanciness 9 | /// but in the interest of keeping like minded code together, keeping the 10 | /// naming convention standard 11 | class NewScreenWizardBloc { 12 | ScreenService _screenService = ScreenService(); 13 | int _margins = 32; //may want to make this user selectable in a future release 14 | 15 | /// Creates a new empty screen 16 | /// Adds in the controls from the model 17 | /// Saves it 18 | Future saveScreen(NewScreenWizardModel model) async { 19 | //create an initial screen in the list / set the active screen to it 20 | await _screenService.createScreen(); 21 | //now that we have an active, lets load in the defaults 22 | await _screenService.initDefaults(); 23 | 24 | //set up the defaults based on the model 25 | _screenService.activeScreenViewModel!.name = model.screenName; 26 | _screenService.activeScreenViewModel!.backgroundColor = Colors.black54; 27 | await _buildControls(model); 28 | 29 | //save it 30 | await _screenService.activeScreenViewModel!.save(); 31 | } 32 | 33 | /// Here we build all of the controls we will add to the new screen 34 | Future _buildControls(NewScreenWizardModel model) async { 35 | //to get workable screen width, we need to take the total width passed in 36 | //then remove a margin for every control we have horizontally, +1 37 | int workableWidth = model.screenWidth.floor() - 38 | (_margins * model.horizontalControlCount) - 39 | (_margins * 2); 40 | //now we divide that by the number of controls, and we have our control width 41 | double controlWidth = (workableWidth / model.horizontalControlCount); 42 | 43 | //now do the same for height 44 | int workableHeight = model.screenHeight.floor() - 45 | (_margins * model.verticalControlCount) - 46 | (_margins * 2); 47 | double controlHeight = (workableHeight / model.verticalControlCount); 48 | 49 | //lets limit the ugly, and hard code a height limit to be 20% max of the screen 50 | if (controlHeight > (workableHeight * .2)) 51 | controlHeight = workableHeight * .2; 52 | 53 | //build the control in a grid fashion, horizontally x vertically 54 | int i = 0; //tracks which control we're on 55 | for (int y = 0; y < model.verticalControlCount; y++) { 56 | for (int x = 0; x < model.horizontalControlCount; x++) { 57 | NewScreenWizardControl element = model.controls[i]; 58 | 59 | //only proceed if the control has valid OR key 60 | if (element.text == null && element.key == null) return; 61 | 62 | _screenService.activeScreenViewModel!.controls! 63 | .add(_buildControl(controlHeight, controlWidth, x, y, element)); 64 | i++; 65 | } 66 | } 67 | } 68 | 69 | /// This builds an individual control we are adding to the new screen 70 | ControlViewModel _buildControl(double controlHeight, double controlWidth, 71 | int x, int y, NewScreenWizardControl element) { 72 | ControlViewModel control = ControlViewModel(); 73 | control.height = controlHeight; 74 | control.width = controlWidth; 75 | control.left = (_margins + ((_margins + controlWidth) * x)); 76 | control.top = (_margins + ((_margins + controlHeight) * y)); 77 | 78 | List mods = []; 79 | if (element.ctrl) mods.add("CTRL"); 80 | if (element.alt) mods.add("ALT"); 81 | if (element.shift) mods.add("SHIFT"); 82 | control.commands 83 | .add(Command(key: element.key, modifiers: mods, activatorType: 0)); 84 | 85 | ControlViewModel defaultControl = 86 | _screenService.defaultControls.defaultButton; 87 | 88 | control.text = element.text; 89 | if (element.isSwitch) { 90 | //special conditions apply 91 | control.type = ControlViewModelType.Toggle; 92 | defaultControl = _screenService.defaultControls.defaultToggle; 93 | control.images.add("toggle_off"); 94 | control.images.add("toggle_on"); 95 | //shrink the switch to make room for text 96 | } else { 97 | control.type = ControlViewModelType.Button; 98 | control.images.add("button_black"); 99 | control.images.add("button_black2"); 100 | } 101 | 102 | control.colors = defaultControl.colors; 103 | return control; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/autoItKeyMap.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | 3 | class AutoItKeyMap { 4 | Map map = LinkedHashMap(); 5 | 6 | AutoItKeyMap() { 7 | //add every char in the english alphabet 8 | int c = "A".codeUnitAt(0); 9 | int end = "Z".codeUnitAt(0); 10 | while (c <= end) { 11 | map[String.fromCharCode(c)] = String.fromCharCode(c); 12 | c++; 13 | } 14 | 15 | for (int number = 0; number <= 9; number++) { 16 | map[number.toString()] = number.toString(); 17 | } 18 | for (int number = 0; number <= 9; number++) { 19 | map["NUMPAD$number"] = "Numpad $number"; 20 | } 21 | map["NUMPADMULT"] = "Numpad *"; 22 | map["NUMPADADD"] = "Numpad +"; 23 | map["NUMPADSUB"] = "Numpad -"; 24 | map["NUMPADDIV"] = "Numpad /"; 25 | map["NUMPADDOT"] = "Numpad ."; 26 | map["NUMPADENTER"] = "Numpad Enter"; 27 | 28 | for (int number = 0; number <= 12; number++) { 29 | map["F$number"] = "F$number"; 30 | } 31 | 32 | map["`"] = "~/`"; 33 | map["!"] = "!"; 34 | map["@"] = "@"; 35 | map["#"] = "#"; 36 | map["\$"] = "\$"; 37 | map["%"] = "%"; 38 | map["^"] = "^"; 39 | map["&"] = "&"; 40 | map["*"] = "*"; 41 | map["("] = "("; 42 | map[")"] = ")"; 43 | map["-"] = "- / _"; 44 | map["="] = "= / +"; 45 | map["["] = "[ / {"; 46 | map["]"] = "] / }"; 47 | map["\\"] = "\\ / |"; 48 | map[";"] = "; / :"; 49 | map["'"] = "' / "; 50 | map[","] = "] = / <"; 51 | map["."] = ". / >"; 52 | map["/"] = "/ / ?"; 53 | 54 | map["SPACE"] = "Space"; 55 | map["ENTER"] = "Enter"; 56 | map["BACKSPACE"] = "Backspace"; 57 | map["DELETE"] = "Delete"; 58 | map["UP"] = "Up arrow"; 59 | map["DOWN"] = "Down arrow"; 60 | map["LEFT"] = "Left arrow"; 61 | map["RIGHT"] = "Right arrow"; 62 | map["HOME"] = "Home"; 63 | map["END"] = "End"; 64 | map["ESCAPE"] = "Escape"; 65 | map["INSERT"] = "Insert"; 66 | map["PGUP"] = "Page Up"; 67 | map["PGDN"] = "Page Down"; 68 | map["TAB"] = "Tab Key"; 69 | map["PRINTSCREEN"] = "Print Screen"; 70 | map["LWIN"] = "Left Windows key"; 71 | map["RWIN"] = "Right Windows key"; 72 | map["NUMLOCK"] = "Numlock"; 73 | map["CAPSLOCK"] = "Capslock"; 74 | map["SCROLLLOCK"] = "Scroll Lock"; 75 | map["BREAK"] = "Ctrl+Break "; 76 | map["PAUSE"] = "Pause"; 77 | map["APPSKEY"] = "Windows App key"; 78 | //this seems unnecessary?? map["SLEEP"] = " Computer SLEEP key"; 79 | //map["LWINDOWN"] = " Holds the left Windows key down until map["LWINUP"] = "is sent"; 80 | //map["RWINDOWN"] = " Holds the right Windows key down until map["RWINUP"] = "is sent"; 81 | 82 | map["VOLUME_MUTE"] = "Mute the volume"; 83 | map["VOLUME_DOWN"] = "Reduce the volume"; 84 | map["VOLUME_UP"] = "Increase the volume"; 85 | map["MEDIA_NEXT"] = "Select next track in media player"; 86 | map["MEDIA_PREV"] = "Select previous track in media player"; 87 | map["MEDIA_STOP"] = "Stop media player"; 88 | map["MEDIA_PLAY_PAUSE"] = "Play/pause media player"; 89 | } 90 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/channel.dart: -------------------------------------------------------------------------------- 1 | class Channel { 2 | static const String _channelName = "ca.coffeeshopstudio.gic"; 3 | 4 | static const String channelUtil = "$_channelName/utils"; 5 | static const String channelView = "$_channelName/views"; 6 | 7 | static const String actionViewEditor = "editor"; 8 | static const String actionViewStart = "start"; 9 | static const String actionViewEdit = "edit"; 10 | static const String actionViewManager = "manager"; 11 | 12 | static const String actionUtilDecrypt = "decrypt"; 13 | static const String actionUtilEncrypt = "encrypt"; 14 | static const String actionGetDownloadFolder = "downloadFolder"; 15 | static const String actionUtilGetSettings = "settings/get"; 16 | static const String actionUtilUpdateDarkMode = "darkmode/set"; 17 | static const String actionUtilUpdateScreens = "screens/upgrade"; 18 | static const String actionCheckDefaults = "defaults"; 19 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/intl/intlFeedback.dart: -------------------------------------------------------------------------------- 1 | enum FeedbackText { 2 | toolbarTitle, 3 | details, 4 | updown, 5 | email, 6 | emailTo, 7 | satisfaction, 8 | githubIssues, 9 | githubIssuesUrl, 10 | } 11 | 12 | class IntlFeedback { 13 | static Map> localizedStrings = { 14 | 'en': { 15 | FeedbackText.toolbarTitle: 'Feedback', 16 | FeedbackText.details: 17 | 'Got an idea for a feature you want? See something you hate? Feedback is always appreciated! You can open an issue directly on GitHub (3rd party website, link below), or if you prefer send me an email. Although I will not share any information sent, please ensure you do not include any sensitive information!', 18 | FeedbackText.githubIssues: 'Github Issue Tracker', 19 | FeedbackText.githubIssuesUrl: 20 | 'https://github.com/Terence-D/GamingInterfaceClientAndroid/issues', 21 | FeedbackText.satisfaction: 'Satisfaction', 22 | FeedbackText.updown: 23 | 'Tap on one of the images below (optionally) to quickly provide a thumbs up or down!', 24 | FeedbackText.email: 'Send Feedback', 25 | FeedbackText.emailTo: 'mailto:support@coffeeshopstudio.ca?subject=GIC', 26 | } 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/intl/intlNewScreenWizard.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/backend/models/intl/localizations.dart'; 3 | 4 | enum NewScreenWizardText { 5 | toolbarTitle, 6 | save, 7 | next, 8 | screenName, 9 | increase, 10 | decrease, 11 | buttonDesign, 12 | buttonNormal, 13 | buttonPressed, 14 | switchDesign, 15 | switchNormal, 16 | switchPressed, 17 | orientation, 18 | layout, 19 | controlsWide, 20 | controlsDepth, 21 | totalControls, 22 | buttonType, 23 | switchType, 24 | quickTap, 25 | ctrl, alt, shift, 26 | errorEnterScreenName, 27 | controlText, 28 | controlCommand, 29 | width, 30 | height 31 | } 32 | 33 | class IntlNewScreenWizard { 34 | BuildContext _context; 35 | 36 | IntlNewScreenWizard(this ._context); 37 | 38 | String text(NewScreenWizardText text) { 39 | return _localizedStrings[Intl.of(_context)?.locale.languageCode]![text]!; 40 | } 41 | 42 | static Map> _localizedStrings = { 43 | 'en': { 44 | NewScreenWizardText.toolbarTitle: 'New Screen Wizard', 45 | NewScreenWizardText.save: "Save", 46 | NewScreenWizardText.next: "Next", 47 | NewScreenWizardText.screenName: 'Screen Name', 48 | NewScreenWizardText.increase: "Add", 49 | NewScreenWizardText.decrease: 'Remove', 50 | NewScreenWizardText.buttonDesign: "Button Design", 51 | NewScreenWizardText.buttonNormal: "Normal", 52 | NewScreenWizardText.buttonPressed: "Pressed", 53 | NewScreenWizardText.switchDesign: 'Switch Design', 54 | NewScreenWizardText.switchNormal: "Normal", 55 | NewScreenWizardText.switchPressed: "Pressed", 56 | NewScreenWizardText.orientation: "Orientation", 57 | NewScreenWizardText.layout: "Layout", 58 | NewScreenWizardText.controlsWide: "Controls Wide", 59 | NewScreenWizardText.controlsDepth: "Controls Deep", 60 | NewScreenWizardText.totalControls: "Total Controls", 61 | NewScreenWizardText.buttonType: "Button", 62 | NewScreenWizardText.switchType: "Switch", 63 | NewScreenWizardText.quickTap: "Quick Mode", 64 | NewScreenWizardText.ctrl: "Ctrl", 65 | NewScreenWizardText.alt: "Alt", 66 | NewScreenWizardText.shift: "Shift", 67 | NewScreenWizardText.errorEnterScreenName: "Please enter a screen name!", 68 | NewScreenWizardText.controlCommand: "Command on press", 69 | NewScreenWizardText.controlText: "Text to Display", 70 | NewScreenWizardText.width: "Width", 71 | NewScreenWizardText.height: "Height" 72 | } 73 | }; 74 | } 75 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/intl/intlOptions.dart: -------------------------------------------------------------------------------- 1 | enum OptionsText { 2 | toolbarTitle, 3 | darkModeTitle, 4 | darkModeText, 5 | soundTitle, 6 | soundText, 7 | vibrationTitle, 8 | vibrationText, 9 | keepScreenOnTitle, 10 | keepScreenOnText, 11 | } 12 | 13 | class IntlOptions { 14 | static Map> localizedStrings = { 15 | 'en': { 16 | OptionsText.toolbarTitle: 'Options', 17 | OptionsText.darkModeTitle: 'Dark Mode', 18 | OptionsText.darkModeText: 19 | 'Enable this for the Dark Theme, disable this for the Light Theme', 20 | OptionsText.soundTitle: 'Sound', 21 | OptionsText.soundText: 22 | 'Enable this an audio sound to be played when a Button or Toggle is activated. Ensure audio is not muted on your device before enabling!', 23 | OptionsText.vibrationTitle: 'Vibration', 24 | OptionsText.vibrationText: 25 | 'Enable this for the device to perform a light vibration when a Button or Toggle is activated', 26 | OptionsText.keepScreenOnTitle: 'Keep Screen On', 27 | OptionsText.keepScreenOnText: 28 | 'Enable this to keep the screen on when in game', 29 | } 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/launcherModel.dart: -------------------------------------------------------------------------------- 1 | /// TODO this should be renamed 2 | class LauncherModel { 3 | String toolbarTitle = ""; 4 | bool firstRun = false; 5 | bool darkMode = true; 6 | bool sound = false; 7 | bool vibration = false; 8 | bool keepScreenOn = false; 9 | String address = ""; 10 | String password = ""; 11 | String port = ""; 12 | List screens = []; 13 | int newScreenid = 0; 14 | } 15 | 16 | class ScreenListItem { 17 | ScreenListItem(this.id, this.name); 18 | 19 | String? name; 20 | final int? id; 21 | } 22 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/networkModel.dart: -------------------------------------------------------------------------------- 1 | import 'package:gic_flutter/src/backend/services/cryptoService.dart'; 2 | 3 | class NetworkModel { 4 | String _password = ""; 5 | String _address = ""; 6 | String _port = ""; 7 | 8 | String get password => _password; 9 | String get address => _address; 10 | String get port => _port; 11 | 12 | void toTest(String password, String address, String port) { 13 | _password = password; 14 | _address = address; 15 | _port = port; 16 | } 17 | 18 | Future init(String unencryptedPassword, String address, String port) async { 19 | _password = await CryptoService.encrypt(unencryptedPassword); 20 | _address = address; 21 | _port = port; 22 | } 23 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/newScreenWizardModel.dart: -------------------------------------------------------------------------------- 1 | class NewScreenWizardModel { 2 | String toolbarTitle = ""; 3 | //These are built in the view and passed back as requires Context 4 | double screenWidth = 0; 5 | double screenHeight = 0; 6 | 7 | String screenName = ""; 8 | bool isLandscape = true; // used for constructing the above screen values. User set 9 | //Grid view related 10 | int horizontalControlCount = 1; 11 | int verticalControlCount = 1; 12 | //default look for both 13 | String buttonNormalImage = ""; 14 | String buttonPressedImage = ""; 15 | String switchNormalImage = ""; 16 | String switchPressedImage = ""; 17 | 18 | late List controls; // our list of controls to create 19 | } 20 | 21 | /// This is used purely for the "new screen" view model 22 | class NewScreenWizardControl { 23 | String text = ""; 24 | String key = ""; 25 | bool isSwitch = false; 26 | bool alt = false; 27 | bool ctrl = false; 28 | bool shift= false; 29 | } 30 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/screen/command.dart: -------------------------------------------------------------------------------- 1 | class Command { 2 | static const int KEY_DOWN = 0; 3 | static const int KEY_UP = 1; 4 | 5 | String? key = "A"; 6 | List? modifiers = []; 7 | int? activatorType = 0; //key down, key up, etc 8 | 9 | Command.empty(); 10 | 11 | Command ({this.key, this.modifiers, this.activatorType}) { 12 | if (this.modifiers == null) { 13 | this.modifiers = []; 14 | } 15 | } 16 | 17 | Map toJson() => 18 | { 19 | 'activatorType': activatorType, 20 | 'key': key, 21 | 'modifier': modifiers 22 | }; 23 | 24 | factory Command.fromJson(Map json) { 25 | if (json['modifier'] == null && json['Modifier'] == null) { 26 | json['modifier'] = []; 27 | } 28 | 29 | //handle both case possibilities 30 | var jsonMods; 31 | List? mods = []; 32 | if (json.containsKey('modifier')) 33 | jsonMods = json['modifier']; 34 | else if (json.containsKey('Modifier')) 35 | jsonMods = json['Modifier']; 36 | if (jsonMods != null) 37 | mods = List.from(jsonMods); 38 | 39 | String? jsonKey = ""; 40 | if (json.containsKey('key')) 41 | jsonKey = json['key']; 42 | else if (json.containsKey('Key')) 43 | jsonKey = json['Key']; 44 | 45 | int? jsonActivator=0; 46 | if (json.containsKey('activatorType')) 47 | jsonActivator = json['activatorType']; 48 | else if (json.containsKey('ActivatorType')) 49 | jsonActivator = json['ActivatorType']; 50 | 51 | return Command( 52 | key: jsonKey, 53 | modifiers: mods, 54 | activatorType: jsonActivator 55 | ); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/screen/controlDefaults.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:gic_flutter/src/backend/models/screen/gicControl.dart'; 5 | import 'package:gic_flutter/src/backend/models/screen/viewModels/controlViewModel.dart'; 6 | import 'package:shared_preferences/shared_preferences.dart'; 7 | 8 | /// This is used to store / save default control values 9 | /// such as backgrounds, sizing, fonts, etc 10 | class ControlDefaults { 11 | final String _imageDefaults = "_image_defaults"; 12 | final String _buttonDefaults = "_button_defaults"; 13 | final String _textDefaults = "_text_defaults"; 14 | final String _toggleDefaults = "_switch_defaults"; 15 | 16 | ControlViewModel defaultImage = ControlViewModel(); 17 | ControlViewModel defaultButton = ControlViewModel(); 18 | ControlViewModel defaultText = ControlViewModel(); 19 | ControlViewModel defaultToggle = ControlViewModel(); 20 | 21 | SharedPreferences _prefs; 22 | 23 | ControlDefaults(this._prefs, int? screenId) { 24 | if (this._prefs.containsKey("v2$screenId$_imageDefaults")) { 25 | Map imageControlMap = 26 | jsonDecode(_prefs.getString("v2$screenId$_imageDefaults") ?? ""); 27 | defaultImage = ControlViewModel.fromJson(imageControlMap); 28 | 29 | Map buttonControlMap = 30 | jsonDecode(_prefs.getString("v2$screenId$_buttonDefaults") ?? ""); 31 | defaultButton = ControlViewModel.fromJson(buttonControlMap); 32 | 33 | Map textControlMap = 34 | jsonDecode(_prefs.getString("v2$screenId$_textDefaults") ?? ""); 35 | defaultText = ControlViewModel.fromJson(textControlMap); 36 | 37 | Map toggleControlMap = 38 | jsonDecode(_prefs.getString("v2$screenId$_toggleDefaults") ?? ""); 39 | defaultToggle = ControlViewModel.fromJson(toggleControlMap); 40 | } else if (_prefs.containsKey("$screenId$_imageDefaults")) { 41 | try { 42 | defaultImage = ControlViewModel.fromLegacyModel( 43 | loadControl("$screenId$_imageDefaults")); 44 | defaultButton = ControlViewModel.fromLegacyModel( 45 | loadControl("$screenId$_buttonDefaults")); 46 | defaultText = ControlViewModel.fromLegacyModel( 47 | loadControl("$screenId$_textDefaults")); 48 | defaultToggle = ControlViewModel.fromLegacyModel( 49 | loadControl("$screenId$_toggleDefaults")); 50 | } catch (ex) { 51 | print(ex); 52 | } 53 | } 54 | 55 | //if nothing was loaded in 56 | if (defaultImage.type != ControlViewModelType.Image) { 57 | defaultImage.type = ControlViewModelType.Image; 58 | defaultImage.images = []; 59 | defaultButton.type = ControlViewModelType.Button; 60 | defaultButton.design = ControlDesignType.Image; 61 | defaultButton.images = []; 62 | defaultButton.colors = []; 63 | defaultButton.colors.add(Colors.blue); 64 | defaultButton.colors.add(Colors.black); 65 | defaultButton.images.add("button_black"); 66 | defaultButton.images.add("button_black2"); 67 | defaultText.type = ControlViewModelType.Text; 68 | defaultToggle.type = ControlViewModelType.Toggle; 69 | defaultToggle.images = []; 70 | defaultToggle.images.add("toggle_off"); 71 | defaultToggle.images.add("toggle_on"); 72 | defaultToggle.colors = []; 73 | defaultToggle.colors.add(Colors.blue); 74 | defaultToggle.colors.add(Colors.black); 75 | } 76 | } 77 | 78 | GicControl loadControl(String preference) { 79 | if (!_prefs.containsKey(preference)) { 80 | return GicControl.empty(); 81 | } else { 82 | Map controlMap = jsonDecode(_prefs.getString(preference) ?? ""); 83 | return GicControl.fromJson(controlMap); 84 | } 85 | } 86 | 87 | bool saveDefaults(int screenId) { 88 | try { 89 | _prefs.setString( 90 | "v2$screenId$_imageDefaults", jsonEncode(defaultImage.toJson())); 91 | _prefs.setString( 92 | "v2$screenId$_buttonDefaults", jsonEncode(defaultButton.toJson())); 93 | _prefs.setString( 94 | "v2$screenId$_textDefaults", jsonEncode(defaultText.toJson())); 95 | _prefs.setString( 96 | "v2$screenId$_toggleDefaults", jsonEncode(defaultToggle.toJson())); 97 | return true; 98 | } catch (_) { 99 | return false; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/screen/controlTypes.dart: -------------------------------------------------------------------------------- 1 | enum Controls { 2 | button, 3 | text, 4 | image, 5 | toggle 6 | } 7 | 8 | class ControlTypes { 9 | static final List buttonDrawables = [ 10 | "button_neon", 11 | "button_neon_dark", 12 | "button_blue", 13 | "button_blue_dark", 14 | "button_green", 15 | "button_green_dark", 16 | "button_green2", 17 | "button_green2_dark", 18 | "button_purple", 19 | "button_purple_dark", 20 | "button_red", 21 | "button_red_dark", 22 | "button_yellow", 23 | "button_yellow_dark", 24 | "button_black", 25 | "button_black_dark", 26 | "button_black2", 27 | "button_black2_dark", 28 | "button_blue2", 29 | "button_blue2_dark", 30 | "button_grey", 31 | "button_grey_dark", 32 | "button_grey2", 33 | "button_grey2_dark", 34 | "button_red2", 35 | "button_red2_dark", 36 | "button_white", 37 | "button_white_dark", 38 | ]; 39 | 40 | static final List toggleDrawables = [ 41 | "switch_off", 42 | "switch_on", 43 | "toggle_off", 44 | "toggle_on", 45 | "lever_off", 46 | "lever_on", 47 | "button_toggle_off", 48 | "button_toggle_on" 49 | ]; 50 | 51 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/screen/fonts.dart: -------------------------------------------------------------------------------- 1 | class Fonts { 2 | static Map list() { 3 | return { 4 | "Lobster-Regular": "Lobster", 5 | "Nunito-Regular": "Nunito", 6 | "Righteous-Regular": "Righteous", 7 | "ShareTech-Regular": "ShareTech", 8 | }; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/screen/gicControl.dart: -------------------------------------------------------------------------------- 1 | import 'command.dart'; 2 | 3 | class GicControl { 4 | static const int TYPE_BUTTON = 0; 5 | static const int TYPE_TEXT = 1; 6 | static const int TYPE_IMAGE = 2; 7 | static const int TYPE_SWITCH = 3; 8 | static const int TYPE_BUTTON_QUICK = 4; 9 | 10 | //this is required for the toggle button, there are 4 stages to track: 11 | //0 - switched off ready for mouse down 12 | //1 - switched off, ready for mouse up 13 | //2 - switched on, ready for mouse down, 14 | //3 - switched on, ready for mouse up 15 | //after 3, we reset back to 0 16 | int? stage = 0; 17 | Command command = Command.empty(); 18 | String? text = "NONE"; 19 | double? left = 140; 20 | double? width = 320; 21 | double? top = 200; 22 | double? height = 120; 23 | int? fontColor = -1; 24 | int? primaryColor = -1; 25 | int? secondaryColor = -1; 26 | int? fontSize = 36; 27 | int viewType = 0; //is it a button, switch, image, etc 28 | int? primaryImageResource = -1;//R.drawable.button_blue; 29 | int? secondaryImageResource = -1;//R.drawable.button_blue_dark; 30 | String primaryImage = ""; 31 | String secondaryImage = ""; 32 | String fontName = ""; 33 | int fontType = 0; 34 | Command commandSecondary = Command.empty(); 35 | 36 | GicControl.empty() { 37 | primaryImage = "button_black"; 38 | secondaryImage = "button_black2"; 39 | } 40 | 41 | GicControl ({ 42 | this.stage, 43 | required this.command, 44 | this.text, 45 | this.left, 46 | this.width, 47 | this.top, 48 | this.height, 49 | this.fontColor, 50 | this.primaryColor, 51 | this.secondaryColor, 52 | this.fontSize, 53 | this.viewType = 0, 54 | this.primaryImageResource, 55 | this.secondaryImageResource, 56 | required this.primaryImage, 57 | required this.secondaryImage, 58 | required this.fontName, 59 | required this.fontType, 60 | required this.commandSecondary 61 | }); 62 | 63 | factory GicControl.fromJson(Map json) { 64 | return GicControl( 65 | stage: json['stage'], 66 | command: Command.fromJson(json['command']), 67 | text: json['text'], 68 | left: json['left'], 69 | width: json['width'].toDouble(), 70 | top: json['top'], 71 | height: json['height'].toDouble(), 72 | fontColor: json['fontColor'], 73 | primaryColor: json['primaryColor'], 74 | secondaryColor: json['secondaryColor'], 75 | fontSize: json['fontSize'], 76 | viewType: json['viewType'], 77 | primaryImageResource: json['primaryImageResource'], 78 | secondaryImageResource: json['secondaryImageResource'], 79 | primaryImage: json['primaryImage'], 80 | secondaryImage: json['secondaryImage'], 81 | fontName: json['fontName'], 82 | fontType: json['fontType'], 83 | commandSecondary: Command.fromJson(json['commandSecondary']), 84 | ); 85 | } 86 | 87 | Map toJson() => 88 | { 89 | 'stage': stage, 90 | 'command': command, 91 | 'text': text, 92 | 'left': left, 93 | 'width': width, 94 | 'top': top, 95 | 'height': height, 96 | 'fontColor': fontColor, 97 | 'primaryColor': primaryColor, 98 | 'secondaryColor': secondaryColor, 99 | 'fontSize': fontSize, 100 | 'viewType': viewType, 101 | 'primaryImageResource': primaryImageResource, 102 | 'secondaryImageResource': secondaryImageResource, 103 | 'primaryImage': primaryImage, 104 | 'secondaryImage': secondaryImage, 105 | 'fontName': fontName, 106 | 'fontType': fontType, 107 | 'commandSecondary': commandSecondary 108 | }; 109 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/screen/screen.dart: -------------------------------------------------------------------------------- 1 | import 'gicControl.dart'; 2 | 3 | class Screen { 4 | static const MAX_CONTROL_SIZE = 800; 5 | 6 | int? screenId = -1; 7 | List? controls = []; 8 | //background 9 | int? newControlId = -1; 10 | int? backgroundColor; 11 | String? backgroundPath; 12 | //context; 13 | String? name; 14 | 15 | Screen({ 16 | this.screenId = -1, 17 | this.controls = const[], 18 | this.backgroundColor = 0, 19 | this.backgroundPath = "", 20 | this.newControlId = -1, 21 | this.name = ""}); 22 | 23 | factory Screen.fromJson(Map json) { 24 | var list = json['controls'] as List; 25 | List jsonControls = []; 26 | list.forEach((value) { jsonControls.add(GicControl.fromJson(value));}); 27 | 28 | return Screen( 29 | screenId: json['screenId'], 30 | controls: jsonControls, 31 | backgroundColor: json['backgroundColor'], 32 | backgroundPath: json['backgroundPath'], 33 | newControlId: json['newControlId'], 34 | name: json['name']); 35 | } 36 | 37 | // factory Screen.fromModel(ScreenViewModel model, double pixelRatio) { 38 | // Screen rv = new Screen(); 39 | // rv.screenId = model.screenId; 40 | // rv.name = model.name; 41 | // model.controls.forEach((element) { 42 | // rv.controls.add(new ControlViewModel.fromModel(element)); 43 | // }); 44 | // rv.newControlId = model.newControlId; 45 | // 46 | // if (model.backgroundColor == -1 || model.backgroundColor == null) 47 | // rv.backgroundColor = Colors.black; 48 | // else 49 | // rv.backgroundColor = _convertJavaColor(model.backgroundColor); 50 | // rv.backgroundPath = model.backgroundPath; 51 | // return rv; 52 | // } 53 | 54 | Map toJson() => 55 | { 56 | 'screenId': screenId, 57 | 'controls': controls, 58 | 'backgroundColor': backgroundColor, 59 | 'backgroundPath': backgroundPath, 60 | 'newControlId': newControlId, 61 | 'name': name, 62 | }; 63 | 64 | int getNewControlId() { 65 | newControlId = newControlId! + 1; 66 | return newControlId! - 1; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/screen/viewModels/drawable.dart: -------------------------------------------------------------------------------- 1 | class Drawable { 2 | final _value; 3 | const Drawable._internal(this._value); 4 | toString() => _value; 5 | 6 | static const Drawable button_neon = Drawable._internal("button_neon"); 7 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/screen/viewModels/font.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Font { 4 | int version = 0; 5 | Color color = Colors.blue; 6 | double size = 36; 7 | String? family = ""; 8 | 9 | Font.empty() { 10 | color = Colors.blue; 11 | size = 36; 12 | family = ""; 13 | } 14 | 15 | Font({this.color = Colors.blue, this.size = 36, this.family = ""}); 16 | 17 | Font.fromJson(Map json) 18 | : version = json['version'], 19 | color = Color(json['color']), 20 | size = json['size'], 21 | family = json['family']; 22 | 23 | Font clone() { 24 | Font clone = Font(); 25 | clone.version = version; 26 | clone.color = color; 27 | clone.size = size; 28 | clone.family = family; 29 | 30 | return clone; 31 | } 32 | 33 | Map toJson() { 34 | 35 | return { 36 | 'version': 2, 37 | 'color': color.value, 38 | 'size': size, 39 | 'family': family 40 | }; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/viewModel.dart: -------------------------------------------------------------------------------- 1 | /// Abstract common class allowing shard view code to be called 2 | abstract class ViewModel { 3 | String get toolbarTitle; 4 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/models/viewSection.dart: -------------------------------------------------------------------------------- 1 | 2 | class ViewSection { 3 | String title = ""; 4 | String text = ""; 5 | String url = ""; 6 | 7 | ViewSection (this.title, this.text, this.url); 8 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/services/compressedFileService.dart: -------------------------------------------------------------------------------- 1 | import 'dart:developer'; 2 | import 'dart:io'; 3 | 4 | import 'package:archive/archive_io.dart'; 5 | import 'package:path/path.dart' as path; 6 | 7 | class CompressedFileService { 8 | /// Extracts the supplied compressed file path to the supplied path 9 | /// screen id saved on success, empty string on fail 10 | static String extract(String file, String tempPath) { 11 | String fileId = ""; 12 | try { 13 | final File compressedFile = File(file); 14 | // Read the Zip file from disk. 15 | final bytes = compressedFile.readAsBytesSync(); 16 | // Decode the Zip file 17 | final archive = ZipDecoder().decodeBytes(bytes); 18 | 19 | // Extract the contents of the Zip archive to the temp path. 20 | for (final file in archive) { 21 | final filename = file.name; 22 | if (file.isFile) { 23 | final data = file.content as List; 24 | File(path.join(tempPath, filename)) 25 | ..createSync(recursive: true) 26 | ..writeAsBytesSync(data); 27 | } 28 | fileId = path.split(filename)[0]; 29 | } 30 | } on Exception catch (e) { 31 | log(e.toString()); 32 | } 33 | return fileId; 34 | } 35 | 36 | /// Creates a compressed file 37 | /// folderToCompress is the folder containing the files we want compressed 38 | /// destinationFolder is the destination folder 39 | /// exportFile is the file we are creating 40 | /// Returns 0 on success, -1 on error 41 | static Future compressFolder(String folderToCompress, String destinationFolder, String? exportFile) async { 42 | //add the zip extension if required 43 | try { 44 | if (!exportFile!.endsWith(".zip")) { 45 | exportFile = exportFile + ".zip"; 46 | } 47 | 48 | Directory source = Directory(folderToCompress); 49 | 50 | ZipFileEncoder zipFileEncoder = ZipFileEncoder(); 51 | zipFileEncoder.create(path.join(destinationFolder, exportFile)); 52 | zipFileEncoder.addDirectory(source); 53 | 54 | zipFileEncoder.close(); 55 | } on Exception catch (e) { 56 | log(e.toString()); 57 | return -1; 58 | } 59 | return 0; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/services/cryptoService.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:typed_data'; 3 | 4 | import 'package:pointycastle/export.dart'; 5 | 6 | class CryptoService { 7 | static final String salt = 'f-NS5Qnhn@sdC%_7RAD3K3GmYU5ZHW*\$'; 8 | static final String passphrase = 9 | 'WCu8rer-kuJ58UZKcz*ABL\$?&=@pw=_d4L\$tr^cfFgdad-NxCUXRUz8LL*_5z?Xm^zFMP4FXRUvdEhNH=kwKJp8^-D3Uf8AG?6DtKrQH%HYC*c6KqW&XR2gF7hndfu+u'; 10 | static final String iv = 'kYW-*%n^t!JkV3FU'; 11 | static final int iterations = 100; 12 | static final int size = 32; 13 | static const Mode = 'CBC'; 14 | 15 | static String encrypt(String toEncrypt) { 16 | Uint8List derivedKey = _buildKey(); 17 | KeyParameter keyParam = KeyParameter(derivedKey); 18 | BlockCipher aes = AESFastEngine(); 19 | Uint8List ivBytes = _createUint8ListFromString(iv); 20 | BlockCipher cipher = CBCBlockCipher(aes); 21 | ParametersWithIV params = ParametersWithIV(keyParam, ivBytes); 22 | 23 | cipher.init(true, params); 24 | 25 | Uint8List textBytes = _createUint8ListFromString(toEncrypt); 26 | Uint8List paddedText = _pad(textBytes, aes.blockSize); 27 | Uint8List cipherBytes = _processBlocks(cipher, paddedText); 28 | 29 | return base64.encode(cipherBytes); 30 | } 31 | 32 | static String decrypt(String toDecrypt) { 33 | Uint8List derivedKey = _buildKey(); 34 | KeyParameter keyParam = KeyParameter(derivedKey); 35 | BlockCipher aes = AESFastEngine(); 36 | Uint8List ivBytes = _createUint8ListFromString(iv); 37 | BlockCipher cipher = CBCBlockCipher(aes); 38 | ParametersWithIV params = ParametersWithIV(keyParam, ivBytes); 39 | 40 | String decryptThis = toDecrypt; 41 | if (decryptThis.length % 4 > 0) { 42 | decryptThis += '=' * (4 - decryptThis.length % 4); 43 | } 44 | 45 | Uint8List cipherBytesFromEncode; 46 | try { 47 | cipherBytesFromEncode = base64.decode(decryptThis); 48 | } catch (e) { 49 | return ""; 50 | } 51 | 52 | Uint8List cipherIvBytes = 53 | Uint8List(cipherBytesFromEncode.length + ivBytes.length) 54 | ..setAll(0, ivBytes) 55 | ..setAll(ivBytes.length, cipherBytesFromEncode); 56 | 57 | cipher.init(false, params); 58 | 59 | int cipherLen = cipherIvBytes.length - aes.blockSize; 60 | Uint8List cipherBytes = Uint8List(cipherLen) 61 | ..setRange(0, cipherLen, cipherIvBytes, aes.blockSize); 62 | Uint8List paddedText = _processBlocks(cipher, cipherBytes); 63 | Uint8List? textBytes = _unpad(paddedText); 64 | 65 | if (textBytes == null) { 66 | return ""; 67 | } 68 | 69 | return String.fromCharCodes(textBytes); 70 | } 71 | 72 | static Uint8List _buildKey() { 73 | if (passphrase.isEmpty) { 74 | throw ArgumentError('passphrase must not be empty'); 75 | } 76 | 77 | Uint8List passphraseBytes = _createUint8ListFromString(passphrase); 78 | Uint8List saltBytes = _createUint8ListFromString(salt); 79 | 80 | Pbkdf2Parameters params = Pbkdf2Parameters(saltBytes, iterations, size); 81 | KeyDerivator keyDerivator = PBKDF2KeyDerivator(HMac(SHA1Digest(), 64)); 82 | keyDerivator.init(params); 83 | 84 | return keyDerivator.process(passphraseBytes); 85 | } 86 | 87 | static Uint8List _pad(Uint8List src, int blockSize) { 88 | var pad = PKCS7Padding(); 89 | pad.init(null); 90 | 91 | int padLength = blockSize - (src.length % blockSize); 92 | var out = Uint8List(src.length + padLength)..setAll(0, src); 93 | pad.addPadding(out, src.length); 94 | 95 | return out; 96 | } 97 | 98 | static Uint8List? _unpad(Uint8List src) { 99 | try { 100 | PKCS7Padding pad = PKCS7Padding(); 101 | pad.init(null); 102 | 103 | int padLength = pad.padCount(src); 104 | int len = src.length - padLength; 105 | 106 | return Uint8List(len)..setRange(0, len, src); 107 | } catch (_) { 108 | return null; 109 | } 110 | } 111 | 112 | static Uint8List _processBlocks(BlockCipher cipher, Uint8List inp) { 113 | var out = Uint8List(inp.lengthInBytes); 114 | 115 | for (var offset = 0; offset < inp.lengthInBytes;) { 116 | var len = cipher.processBlock(inp, offset, out, offset); 117 | offset += len; 118 | } 119 | 120 | return out; 121 | } 122 | 123 | static Uint8List _createUint8ListFromString(String s) { 124 | Uint8List ret = Uint8List.fromList(s.codeUnits); 125 | return ret; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/services/firstRunService.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | 3 | class FirstRunService { 4 | static FirstRunService _instance = FirstRunService(); 5 | static SharedPreferences? _preferences; 6 | static const String _prefFirstRun = "firstRun"; //show the whole intro thing 7 | 8 | static Future getInstance() async { 9 | if (_preferences == null) { 10 | _preferences = await SharedPreferences.getInstance(); 11 | } 12 | 13 | return _instance; 14 | } 15 | 16 | dynamic _getBoolFromDisk(String key) { 17 | Object? value = true; 18 | if (_preferences!.containsKey(key)) { 19 | value = _preferences!.get(key); 20 | } 21 | return value; 22 | } 23 | 24 | void _saveBoolToDisk(String key, bool value){ 25 | _preferences!.setBool(key, value); 26 | } 27 | 28 | bool get firstRun { 29 | bool firstRun = _getBoolFromDisk(_prefFirstRun); 30 | if (firstRun) { 31 | _saveBoolToDisk(_prefFirstRun, false); 32 | } 33 | return firstRun; 34 | } 35 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/backend/services/networkService.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:developer'; 3 | 4 | import 'package:gic_flutter/src/backend/models/networkModel.dart'; 5 | import 'package:gic_flutter/src/backend/models/screen/command.dart'; 6 | import 'package:gic_flutter/src/views/launcher/screenList.dart'; 7 | import 'package:http/http.dart' as http; 8 | import 'package:http/http.dart'; 9 | 10 | enum NetworkResponse { Ok, OutOfDate, Error, Unauthorized } 11 | 12 | class NetworkService { 13 | static final String serverApiVersion = "2.1.0.1"; 14 | 15 | static Future sendCommand( 16 | NetworkModel networkModel, String command, Command keystroke) async { 17 | String basicAuth = 18 | base64Encode(Latin1Codec().encode('gic:${networkModel.password}')); 19 | Map headers = Map(); 20 | headers['Content-Type'] = 'application/json; charset=UTF-8'; 21 | headers["Authorization"] = 'Basic $basicAuth'; 22 | 23 | String body = json.encode(keystroke); 24 | NetworkResponse response = await http 25 | .post( 26 | Uri.http("${networkModel.address}:${networkModel.port}", 27 | "/api/$command"), 28 | body: body, 29 | headers: headers) 30 | .timeout(const Duration(seconds: 5)) 31 | .then((response) { 32 | if (response.statusCode != 401) 33 | return NetworkResponse.Ok; 34 | else 35 | return NetworkResponse.Unauthorized; 36 | }).catchError((err) { 37 | log(err.toString()); 38 | return NetworkResponse.Error; 39 | }); 40 | 41 | return response; 42 | } 43 | 44 | static Future checkVersion(NetworkModel networkModel) async { 45 | Uri url = Uri.http("${networkModel.address}:${networkModel.port}", "api/version"); 46 | try { 47 | Map headers = Map(); 48 | String basicAuth = 49 | base64Encode(Latin1Codec().encode('gic:${networkModel.password}')); 50 | headers["Authorization"] = 'Basic $basicAuth'; 51 | Response response = await http.post(url, headers: headers).timeout(const Duration(seconds: 5)); 52 | 53 | if (response.statusCode < 500) { 54 | // If the server did return a 200 OK response then parse the JSON. 55 | if (response.statusCode == 401) 56 | return NetworkResponse.Unauthorized; 57 | VersionResponse versionResponse =VersionResponse.fromJson(jsonDecode(response.body)); 58 | if (versionResponse.version == serverApiVersion) { 59 | return NetworkResponse.Ok; 60 | } else { 61 | return NetworkResponse.OutOfDate; 62 | } 63 | } else 64 | return NetworkResponse.Error; 65 | } catch (exception) { 66 | return NetworkResponse.Error; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/flavor.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | 3 | enum BuildFlavor { other, gplay } 4 | 5 | BuildEnvironment? _env; 6 | 7 | BuildEnvironment? get env => _env; 8 | 9 | class BuildEnvironment { 10 | final BuildFlavor flavor; 11 | 12 | BuildEnvironment._init({required this.flavor}); 13 | 14 | static void init({@required flavor}) => 15 | _env ??= BuildEnvironment._init(flavor: flavor); 16 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/main_gplay.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/service_locator.dart'; 3 | import 'package:gic_flutter/src/theme/theme.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'app.dart'; 6 | import 'flavor.dart'; 7 | 8 | Future main() async { 9 | BuildEnvironment.init(flavor: BuildFlavor.gplay); 10 | var myApp = GicApp(); 11 | var myTheme = CustomTheme( 12 | initialThemeKey: ThemeKeys.DARK, 13 | child: myApp, 14 | ); 15 | WidgetsFlutterBinding.ensureInitialized(); 16 | await setupLocator(); 17 | runApp(myTheme); 18 | } 19 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/main_other.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/service_locator.dart'; 3 | import 'package:gic_flutter/src/theme/theme.dart'; 4 | import 'app.dart'; 5 | import 'flavor.dart'; 6 | 7 | Future main() async { 8 | BuildEnvironment.init(flavor: BuildFlavor.other); 9 | var myApp = GicApp(); 10 | var myTheme = CustomTheme( 11 | initialThemeKey: ThemeKeys.DARK, 12 | child: myApp, 13 | ); 14 | WidgetsFlutterBinding.ensureInitialized(); 15 | await setupLocator(); 16 | runApp(myTheme); 17 | } 18 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/service_locator.dart: -------------------------------------------------------------------------------- 1 | import 'package:get_it/get_it.dart'; 2 | 3 | import 'backend/services/firstRunService.dart'; 4 | 5 | GetIt locator = GetIt.instance; 6 | 7 | Future setupLocator() async { 8 | var instance = await FirstRunService.getInstance(); 9 | locator.registerSingleton(instance); 10 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/theme/dimensions.dart: -------------------------------------------------------------------------------- 1 | double activityMargin = 16; 2 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/theme/style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DarkColors { 4 | 5 | } 6 | 7 | ThemeData myDarkTheme() { 8 | return ThemeData( 9 | primaryColor: Color(0xff3F51B5), 10 | primaryColorDark: Color(0xff2A41B3), 11 | scaffoldBackgroundColor: Color(0xFF383838), 12 | canvasColor: Color(0xFF383838), 13 | //buttonColor: Color(0xff575757), 14 | appBarTheme: const AppBarTheme( 15 | color: Colors.indigo, 16 | iconTheme: IconThemeData(color: Colors.white), 17 | foregroundColor: Color(0xA1F8F8F8) 18 | ), 19 | snackBarTheme: const SnackBarThemeData( 20 | actionTextColor: Colors.blue, 21 | backgroundColor: Colors.black54, 22 | contentTextStyle: TextStyle(color: Colors.white), 23 | ), 24 | // Define the default TextTheme. Use this to specify the default 25 | // text styling for headlines, titles, bodies of text, and more. 26 | textTheme: TextTheme( 27 | bodyMedium: TextStyle(color: Color(0xA1F8F8F8)) 28 | ), colorScheme: ColorScheme.fromSwatch().copyWith(secondary: Color(0xff43a047),brightness: Brightness.dark, 29 | 30 | ).copyWith(error: Color(0xffF44336)), 31 | ); 32 | } 33 | 34 | ThemeData myLightTheme() { 35 | return ThemeData( 36 | brightness: Brightness.light, 37 | 38 | primaryColor: Color(0xff3F51B5), 39 | primaryColorDark: Color(0xff2A41B3), 40 | scaffoldBackgroundColor: Color(0xffffffff), 41 | canvasColor: Color(0xFF383838), 42 | 43 | // Define the default TextTheme. Use this to specify the default 44 | // text styling for headlines, titles, bodies of text, and more. 45 | textTheme: TextTheme( 46 | bodyMedium: TextStyle(color: Color(0xFF383838)) 47 | ), colorScheme: ColorScheme.fromSwatch().copyWith(secondary: Color(0xff43a047)).copyWith(error: Color(0xffF44336)), 48 | ); 49 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/theme/theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/theme/style.dart'; 3 | 4 | enum ThemeKeys { LIGHT, DARK } 5 | 6 | class MyAppThemes { 7 | static final lightTheme = ThemeData( 8 | primaryColor: myDarkTheme().primaryColor, 9 | brightness: Brightness.light, 10 | ); 11 | 12 | static final darkTheme = ThemeData( 13 | primaryColor: myLightTheme().primaryColor, 14 | brightness: Brightness.dark, 15 | ); 16 | } 17 | 18 | class Themes { 19 | static ThemeData getThemeFromKey(ThemeKeys themeKey) { 20 | switch (themeKey) { 21 | case ThemeKeys.LIGHT: 22 | return ThemeData.light(); 23 | case ThemeKeys.DARK: 24 | return ThemeData.dark(); 25 | default: 26 | return ThemeData.dark(); 27 | } 28 | } 29 | } 30 | 31 | class _CustomTheme extends InheritedWidget { 32 | final CustomThemeState data; 33 | 34 | _CustomTheme({ 35 | required this.data, 36 | Key? key, 37 | required Widget child, 38 | }) : super(key: key, child: child); 39 | 40 | @override 41 | bool updateShouldNotify(_CustomTheme oldWidget) { 42 | return true; 43 | } 44 | } 45 | 46 | class CustomTheme extends StatefulWidget { 47 | final Widget child; 48 | final ThemeKeys initialThemeKey; 49 | 50 | const CustomTheme({ 51 | Key? key, 52 | required this.initialThemeKey, 53 | required this.child, 54 | }) : super(key: key); 55 | 56 | @override 57 | CustomThemeState createState() => CustomThemeState(); 58 | 59 | static ThemeData of(BuildContext context) { 60 | _CustomTheme? inherited = context.dependOnInheritedWidgetOfExactType<_CustomTheme>(); 61 | return inherited!.data.theme; 62 | } 63 | 64 | static CustomThemeState instanceOf(BuildContext context) { 65 | _CustomTheme? inherited = context.dependOnInheritedWidgetOfExactType<_CustomTheme>(); 66 | return inherited!.data; 67 | } 68 | } 69 | 70 | class CustomThemeState extends State { 71 | late ThemeData _theme; 72 | 73 | ThemeData get theme => _theme; 74 | 75 | @override 76 | void initState() { 77 | _theme = Themes.getThemeFromKey(widget.initialThemeKey); 78 | super.initState(); 79 | } 80 | 81 | void changeTheme(ThemeKeys themeKey) { 82 | setState(() { 83 | _theme = Themes.getThemeFromKey(themeKey); 84 | }); 85 | } 86 | 87 | @override 88 | Widget build(BuildContext context) { 89 | return _CustomTheme( 90 | data: this, 91 | key: null, 92 | child: widget.child, 93 | ); 94 | } 95 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/about/aboutVM.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | import 'package:gic_flutter/src/backend/models/viewModel.dart'; 4 | import 'package:gic_flutter/src/backend/models/viewSection.dart'; 5 | 6 | class AboutVM implements ViewModel { 7 | String toolbarTitle = ""; 8 | 9 | String appName = " "; 10 | String versionText = ""; 11 | String libraryTitle = ""; 12 | String emailTo = ""; 13 | String emailTitle = ""; 14 | String url = ""; 15 | List? libraries; 16 | ViewSection legal = ViewSection("","",""); 17 | ViewSection server = ViewSection("","",""); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/about/aboutView.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/backend/models/viewModel.dart'; 3 | import 'package:gic_flutter/src/backend/models/viewSection.dart'; 4 | import 'package:gic_flutter/src/theme/dimensions.dart' as dim; 5 | 6 | import '../basePage.dart'; 7 | import 'aboutPresentation.dart'; 8 | import 'aboutVM.dart'; 9 | 10 | class AboutView extends BasePage { 11 | @override 12 | AboutViewState createState() { 13 | return AboutViewState(); 14 | } 15 | } 16 | 17 | class AboutViewState extends BaseState { 18 | AboutVM viewModel = AboutVM(); 19 | 20 | @override 21 | void initState() { 22 | presentation = AboutPresentation(this); 23 | super.initState(); 24 | } 25 | 26 | @override 27 | void onLoadComplete(ViewModel viewModel) { 28 | setState(() { 29 | this.viewModel = viewModel as AboutVM; 30 | }); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | String title = " "; 36 | title = viewModel.toolbarTitle; 37 | return Scaffold( 38 | appBar: AppBar( 39 | automaticallyImplyLeading: true, 40 | title: Text(title), 41 | ), 42 | body: SingleChildScrollView( 43 | child: Container( 44 | margin: EdgeInsets.all(dim.activityMargin), 45 | child: Column( 46 | crossAxisAlignment: CrossAxisAlignment.center, 47 | children: [ 48 | header(viewModel.appName, Theme.of(context).textTheme.headlineMedium), 49 | Text(viewModel.versionText), 50 | link(viewModel.url), 51 | section(viewModel.server, centered: true), 52 | section(viewModel.legal, centered: true), 53 | header(viewModel.libraryTitle), 54 | _libraries(viewModel.libraries), 55 | ], 56 | ), 57 | ), 58 | ), 59 | ); 60 | } 61 | 62 | Widget _libraries(List? sections) { 63 | if (sections != null) { 64 | List widgets = []; 65 | TextStyle? textStyle = Theme.of(context).textTheme.titleMedium; 66 | sections.forEach( 67 | (s) => widgets.add(section(s, optionalHeaderStyle: textStyle))); 68 | 69 | return Column( 70 | crossAxisAlignment: CrossAxisAlignment.start, 71 | children: widgets, 72 | ); 73 | } 74 | return Column(); 75 | } 76 | 77 | noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); 78 | } 79 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/accentButton.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AccentButton extends StatelessWidget { 4 | final VoidCallback? onPressed; 5 | final Widget? child; 6 | 7 | const AccentButton({this.child, this.onPressed, Key? key}) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | final theme = Theme.of(context); 12 | 13 | return ElevatedButton( 14 | onPressed: onPressed, 15 | child: child, 16 | // style: ElevatedButton.styleFrom(backgroundColor: theme.colorScheme.primary, 17 | // ), 18 | // textColor: theme.accentTextTheme.button.color, 19 | // highlightColor: theme.accentColor, 20 | ); 21 | } 22 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/basePage.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_linkify/flutter_linkify.dart'; 3 | import 'package:gic_flutter/src/backend/models/viewModel.dart'; 4 | import 'package:gic_flutter/src/backend/models/viewSection.dart'; 5 | import 'package:url_launcher/url_launcher.dart'; 6 | 7 | abstract class BasePresentation { 8 | void buildVM(BuildContext context); 9 | } 10 | 11 | abstract class BasePage extends StatefulWidget { 12 | BasePage({Key? key}) : super(key: key); 13 | } 14 | 15 | abstract class BaseState extends State with WidgetsBindingObserver { 16 | BasePresentation? presentation; 17 | 18 | @override 19 | void initState() { 20 | WidgetsBinding.instance.addObserver(this); 21 | super.initState(); 22 | } 23 | 24 | @override 25 | void didChangeDependencies() { 26 | presentation?.buildVM(context); 27 | super.didChangeDependencies(); 28 | } 29 | 30 | // void onLoadComplete(ViewModel viewModel); 31 | // 32 | // void onError(int errorType); 33 | // 34 | @override 35 | void dispose() { 36 | WidgetsBinding.instance.removeObserver(this); 37 | super.dispose(); 38 | } 39 | 40 | Widget section(ViewSection model, {TextStyle? optionalHeaderStyle, bool centered = false}) { 41 | var align = CrossAxisAlignment.start; 42 | if (centered) { 43 | align = CrossAxisAlignment.center; 44 | } 45 | return 46 | Column( 47 | crossAxisAlignment: align, 48 | children: [ 49 | Padding( 50 | padding: const EdgeInsets.fromLTRB(0, 12, 0, 2), 51 | child: header(model.title, optionalHeaderStyle), 52 | ), 53 | Text(model.text), 54 | link(model.url)] 55 | ); 56 | } 57 | 58 | Widget link(String link) { 59 | return Linkify( 60 | onOpen: (link) async { 61 | if (await canLaunch(link.url)) { 62 | await launch(link.url); 63 | } else { 64 | throw 'Could not launch $link'; 65 | } 66 | }, 67 | text: link 68 | ); 69 | } 70 | 71 | Widget header(String text, [TextStyle? textStyle]) { 72 | if (textStyle == null) { 73 | textStyle = Theme.of(context).textTheme.headlineSmall; 74 | } 75 | return Text( 76 | text, 77 | style: textStyle, 78 | ); 79 | } 80 | 81 | void onLoadComplete(ViewModel viewModel) {} 82 | 83 | void onError(int i) {} 84 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/feedback/feedbackPresentation.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:gic_flutter/src/backend/models/intl/intlFeedback.dart'; 3 | import 'package:gic_flutter/src/backend/models/intl/localizations.dart'; 4 | import 'package:gic_flutter/src/views/basePage.dart'; 5 | 6 | import 'feedbackVM.dart'; 7 | 8 | class FeedbackPresentation implements BasePresentation { 9 | BaseState _contract; 10 | 11 | FeedbackPresentation(this._contract); 12 | 13 | Future buildVM(BuildContext context) async { 14 | FeedbackVM _viewModel = FeedbackVM(); 15 | 16 | _viewModel.toolbarTitle = 17 | Intl.of(context)!.feedback(FeedbackText.toolbarTitle); 18 | _viewModel.details = Intl.of(context)!.feedback(FeedbackText.details); 19 | _viewModel.updown = Intl.of(context)!.feedback(FeedbackText.updown); 20 | _viewModel.email = Intl.of(context)!.feedback(FeedbackText.email); 21 | _viewModel.emailTo = Intl.of(context)!.feedback(FeedbackText.emailTo); 22 | _viewModel.satisfaction = Intl.of(context)!.feedback(FeedbackText.satisfaction); 23 | _viewModel.githubIssues = Intl.of(context)!.feedback(FeedbackText.githubIssues); 24 | _viewModel.githubIssuesUrl = Intl.of(context)!.feedback(FeedbackText.githubIssuesUrl); 25 | 26 | _contract.onLoadComplete(_viewModel); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/feedback/feedbackVM.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | import 'package:gic_flutter/src/backend/models/viewModel.dart'; 4 | 5 | class FeedbackVM implements ViewModel { 6 | String toolbarTitle = ""; 7 | String details = ""; 8 | String updown = ""; 9 | String email = ""; 10 | String emailTo = ""; 11 | String satisfaction = ""; 12 | String githubIssues = ""; 13 | String githubIssuesUrl = ""; 14 | } 15 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/feedback/feedbackView.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/backend/models/viewModel.dart'; 3 | import 'package:gic_flutter/src/theme/dimensions.dart' as dim; 4 | import 'package:gic_flutter/src/views/feedback/feedbackVM.dart'; 5 | import 'package:url_launcher/url_launcher.dart'; 6 | 7 | import '../basePage.dart'; 8 | import 'FeedbackPresentation.dart'; 9 | 10 | class FeedbackView extends BasePage { 11 | @override 12 | FeedbackViewState createState() { 13 | return FeedbackViewState(); 14 | } 15 | } 16 | 17 | class FeedbackViewState extends BaseState { 18 | FeedbackVM viewModel = FeedbackVM(); 19 | String _feedback = ""; 20 | List _isSelected = [false, false, false]; 21 | 22 | @override 23 | void initState() { 24 | presentation = FeedbackPresentation(this); 25 | super.initState(); 26 | } 27 | 28 | @override 29 | void onLoadComplete(ViewModel viewModel) { 30 | setState(() { 31 | this.viewModel = viewModel as FeedbackVM; 32 | }); 33 | } 34 | 35 | @override 36 | Widget build(BuildContext context) { 37 | String title = " "; 38 | title = viewModel.toolbarTitle; 39 | return Scaffold( 40 | appBar: AppBar( 41 | automaticallyImplyLeading: true, 42 | title: Text(title), 43 | ), 44 | body: SingleChildScrollView( 45 | child: Container( 46 | margin: EdgeInsets.all(dim.activityMargin), 47 | child: Column( 48 | crossAxisAlignment: CrossAxisAlignment.center, 49 | children: [ 50 | Text(viewModel.details), 51 | ElevatedButton( 52 | child: Text(viewModel.githubIssues), 53 | onPressed: () async { 54 | String url = 55 | viewModel.githubIssuesUrl; 56 | if (await canLaunch(url)) 57 | await launch(url); 58 | else 59 | // can't launch url, there is some error 60 | throw "Could not launch $url"; 61 | },), 62 | Padding( 63 | padding: const EdgeInsets.fromLTRB(0,32,0,0), 64 | child: header(viewModel.satisfaction), 65 | ), 66 | Text(viewModel.updown), 67 | Padding( 68 | padding: const EdgeInsets.fromLTRB(32.0, 0, 32.0, 0), 69 | child: ToggleButtons( 70 | children: [ 71 | Icon(Icons.sentiment_satisfied, size: 64), 72 | Icon(Icons.sentiment_neutral, size: 64), 73 | Icon(Icons.sentiment_dissatisfied, size: 64), 74 | ], 75 | onPressed: (int index) { 76 | setState(() { 77 | for (int buttonIndex = 0; buttonIndex < _isSelected.length; buttonIndex++) { 78 | if (buttonIndex == index) { 79 | _isSelected[buttonIndex] = true; 80 | } else { 81 | _isSelected[buttonIndex] = false; 82 | } 83 | } 84 | _pickSatisfaction(); 85 | }); 86 | }, 87 | isSelected: _isSelected, 88 | ), 89 | ), 90 | Padding( 91 | padding: const EdgeInsets.all(32.0), 92 | child: ElevatedButton( 93 | // onPressed: , 94 | child: Row( 95 | mainAxisAlignment: MainAxisAlignment.center, 96 | children: [ 97 | Text(viewModel.email), 98 | Padding(padding: const EdgeInsets.all(8.0)), 99 | Icon(Icons.email), 100 | ], 101 | ), onPressed: () { 102 | _sendEmail(viewModel.emailTo); 103 | },), 104 | ) 105 | ], 106 | ), 107 | ), 108 | )); 109 | } 110 | 111 | _sendEmail(email) async { 112 | if (await canLaunch(email)) { 113 | await launch("$email$_feedback"); 114 | } else { 115 | throw 'Could not launch $link'; 116 | } 117 | } 118 | 119 | _pickSatisfaction() { 120 | if (_isSelected[0]) 121 | _feedback = " :)"; 122 | else if (_isSelected[1]) 123 | _feedback = " :|"; 124 | else 125 | _feedback = " :("; 126 | } 127 | 128 | noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); 129 | } 130 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/intro/introView.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:gic_flutter/src/backend/models/intl/localizations.dart'; 4 | import 'package:gic_flutter/src/theme/theme.dart'; 5 | import 'package:gic_flutter/src/views/launcher/launcher.dart'; 6 | import 'package:gic_flutter/src/views/intro/introPresentation.dart'; 7 | import 'package:introduction_screen/introduction_screen.dart'; 8 | 9 | class IntroView extends StatefulWidget{ 10 | 11 | const IntroView({Key? key}) : super(key: key); 12 | 13 | @override 14 | IntroViewState createState() { 15 | return IntroViewState(); 16 | } 17 | } 18 | 19 | class IntroViewState extends State implements IntroViewContract { 20 | List? _pages; 21 | Color? _primaryColor; 22 | @override 23 | initState() { 24 | super.initState(); 25 | } 26 | 27 | @override 28 | void didChangeDependencies() { 29 | super.didChangeDependencies(); 30 | IntroPresentation(this).loadPages(context); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | SystemChrome.setSystemUIOverlayStyle( 36 | SystemUiOverlayStyle.dark.copyWith(statusBarColor: Colors.transparent), 37 | ); 38 | 39 | _primaryColor = CustomTheme.of(context).primaryColor; 40 | if (_pages == null) { 41 | return Stack( 42 | children: [ 43 | Opacity( 44 | opacity: 0.3, 45 | child: const ModalBarrier(dismissible: false, color: Colors.grey), 46 | ), 47 | Center( 48 | child: CircularProgressIndicator(), 49 | ), 50 | ], 51 | ); 52 | } else { 53 | return IntroductionScreen( 54 | pages: _pages, 55 | dotsDecorator: DotsDecorator( 56 | activeColor: _primaryColor, 57 | ), 58 | onDone: () => _onIntroEnd(context), 59 | //onSkip: () => _onIntroEnd(context), // You can override onSkip callback 60 | showSkipButton: true, 61 | skipOrBackFlex: 0, 62 | nextFlex: 0, 63 | skip: Text(Intl.of(context)!.onboardSkip), 64 | next: const Icon(Icons.arrow_forward), 65 | done: Text(Intl.of(context)!.onboardDone, style: TextStyle(fontWeight: FontWeight.w600)), 66 | ); 67 | } 68 | } 69 | 70 | @override 71 | void onIntroLoadCompleted(List pages) { 72 | setState(() { 73 | _pages = pages; 74 | }); 75 | } 76 | 77 | void _onIntroEnd(context) { 78 | Navigator.pushReplacement(context, 79 | MaterialPageRoute(builder: (context) => Launcher()) 80 | ); 81 | } 82 | } 83 | 84 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/intro/screenListWidget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/theme/theme.dart'; 3 | 4 | class ScreenItem { 5 | String title; 6 | bool selected = false; 7 | ScreenItem(this.title); 8 | } 9 | 10 | class ScreenListWidget extends StatefulWidget { 11 | final List _screens; 12 | ScreenListWidget(this._screens, {Key? key}) : super(key: key); 13 | 14 | @override 15 | _ScreenListWidgetState createState() => _ScreenListWidgetState(); 16 | } 17 | 18 | class _ScreenListWidgetState extends State { 19 | @override 20 | Widget build(BuildContext context) { 21 | Color accent = CustomTheme 22 | .of(context) 23 | .primaryColor; 24 | return SizedBox( 25 | width: 200.0, 26 | height: 200.0, 27 | child: ListView( 28 | children: [ 29 | Ink( 30 | color: widget._screens[0].selected ? accent : Colors.transparent, 31 | child: ListTile( 32 | title: Text(widget._screens[0].title), 33 | onTap: () { 34 | setState(() { 35 | widget._screens[0].selected = ! widget._screens[0].selected; 36 | }); 37 | }, 38 | ) 39 | ), 40 | Ink( 41 | color: widget._screens[1].selected ? accent : Colors.transparent, 42 | child: ListTile( 43 | title: Text(widget._screens[1].title), 44 | onTap: () { 45 | setState(() { 46 | widget._screens[1].selected = ! widget._screens[1].selected; 47 | }); 48 | }, 49 | ) 50 | ), 51 | ], 52 | ), 53 | ); 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/intro/screenSizeWidget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ScreenSizeWidget extends StatefulWidget { 4 | final Function(String) onSelectParam; 5 | 6 | ScreenSizeWidget(this.onSelectParam, {Key? key}) : super(key: key); 7 | 8 | @override 9 | _ScreenSizeWidgetState createState() => _ScreenSizeWidgetState(); 10 | } 11 | 12 | class _ScreenSizeWidgetState extends State { 13 | List dropdownItems = ['Phone', 'Small Tablet', 'Large Tablet']; 14 | String device = ""; 15 | _ScreenSizeWidgetState() { 16 | device = (dropdownItems[0]); 17 | } 18 | @override 19 | Widget build(BuildContext context) { 20 | return SizedBox( 21 | width: 150.0, 22 | height: 100.0, 23 | child: Center( 24 | child: getDropdown() 25 | ), 26 | ); 27 | } 28 | DropdownButton getDropdown() { 29 | return DropdownButton( 30 | value: device, 31 | elevation: 16, 32 | underline: Container( 33 | height: 2, 34 | ), 35 | onChanged: (String? newValue) { 36 | setState(() { 37 | device = newValue!; 38 | widget.onSelectParam(device); 39 | }); 40 | }, 41 | items: dropdownItems.map>((String value) { 42 | return DropdownMenuItem( 43 | value: value, 44 | child: Text(value), 45 | ); 46 | }).toList(), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/menuOption.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MenuOption { 4 | const MenuOption({this.title = "", this.icon = Icons.new_label}); 5 | 6 | final String title; 7 | final IconData icon; 8 | } 9 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/newScreenWizard/controlDesignWidget.dart: -------------------------------------------------------------------------------- 1 | // this widget handles setting if we are portrait or landscape mode 2 | import 'package:flutter/material.dart'; 3 | import 'package:gic_flutter/src/backend/models/intl/intlNewScreenWizard.dart'; 4 | 5 | import 'newScreenWizard.dart'; 6 | 7 | class ControlDesignWidget extends StatefulWidget { 8 | final NewScreenWizardState state; 9 | 10 | const ControlDesignWidget ( this.state, {Key? key }): super(key: key); 11 | 12 | @override 13 | State createState() => ControlDesignState(); 14 | 15 | } 16 | 17 | class ControlDesignState extends State { 18 | Icon? icon; 19 | 20 | @override 21 | void initState() { 22 | _setButton(); 23 | super.initState(); 24 | } 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Container( 29 | child: Column( 30 | crossAxisAlignment: CrossAxisAlignment.center, 31 | children: [ 32 | Text( 33 | widget.state.translation.text(NewScreenWizardText.buttonDesign), 34 | style: Theme.of(context).textTheme.headlineSmall, 35 | ), 36 | Container( 37 | height: 50.0, 38 | child: ElevatedButton( 39 | onPressed: () {}, 40 | // shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(80.0)), 41 | // padding: EdgeInsets.all(0.0), 42 | child: Ink( 43 | decoration: BoxDecoration( 44 | gradient: LinearGradient(colors: [Color(0xff374ABE), Color(0xff64B6FF)], 45 | begin: Alignment.topRight, 46 | ), 47 | ), 48 | child: Container( 49 | constraints: BoxConstraints(maxWidth: 300.0, minHeight: 50.0), 50 | alignment: Alignment.center, 51 | child: Text( 52 | "Login", 53 | textAlign: TextAlign.center, 54 | style: TextStyle( 55 | color: Colors.white 56 | ), 57 | ), 58 | ), 59 | ), 60 | ), 61 | ), 62 | ], 63 | ), 64 | ); 65 | } 66 | 67 | // void _updateControlDesign() { 68 | // setState(() { 69 | // widget.state.viewModel.isLandscape = !widget.state.viewModel.isLandscape; 70 | // _setButton(); 71 | // }); 72 | // } 73 | 74 | void _setButton() { 75 | icon = Icon(Icons.screen_lock_portrait); 76 | if (widget.state.viewModel.isLandscape) { 77 | icon = Icon(Icons.screen_lock_landscape); 78 | } 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/newScreenWizard/layoutWidget.dart: -------------------------------------------------------------------------------- 1 | // this widget handles setting if we are portrait or landscape mode 2 | import 'package:flutter/material.dart'; 3 | import 'package:gic_flutter/src/backend/models/intl/intlNewScreenWizard.dart'; 4 | 5 | import 'newScreenWizard.dart'; 6 | 7 | class LayoutWidget extends StatefulWidget { 8 | final NewScreenWizardState state; 9 | 10 | const LayoutWidget ( this.state, {Key? key }): super(key: key); 11 | 12 | @override 13 | State createState() => LayoutState(); 14 | } 15 | 16 | class LayoutState extends State { 17 | @override 18 | Widget build(BuildContext context) { 19 | return Container( 20 | child: Column( 21 | crossAxisAlignment: CrossAxisAlignment.center, 22 | children: [ 23 | Text( 24 | widget.state.translation.text(NewScreenWizardText.layout), 25 | style: Theme.of(context).textTheme.headlineSmall, 26 | ), 27 | Row( 28 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 29 | children: [ 30 | ElevatedButton(onPressed: () { _updateCount(horizontal: -1); }, 31 | child: Text("${widget.state.translation.text(NewScreenWizardText.decrease)}"),), 32 | Text("${widget.state.viewModel.horizontalControlCount} ${widget.state.translation.text(NewScreenWizardText.controlsWide)}"), 33 | ElevatedButton(onPressed: () { _updateCount(horizontal: 1); }, 34 | child: Text("${widget.state.translation.text(NewScreenWizardText.increase)}"),), 35 | ], 36 | ), 37 | Row( 38 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 39 | children: [ 40 | ElevatedButton(onPressed: () { _updateCount(vertical: -1); }, 41 | child: Text("${widget.state.translation.text(NewScreenWizardText.decrease)}"),), 42 | Text("${widget.state.viewModel.verticalControlCount} ${widget.state.translation.text(NewScreenWizardText.controlsDepth)}"), 43 | ElevatedButton(onPressed: () { _updateCount(vertical: 1); }, 44 | child: Text("${widget.state.translation.text(NewScreenWizardText.increase)}"),), 45 | ], 46 | ), 47 | Text("${widget.state.viewModel.horizontalControlCount * widget.state.viewModel.verticalControlCount } ${widget.state.translation.text(NewScreenWizardText.totalControls)}",), 48 | ] 49 | ) 50 | ); 51 | } 52 | 53 | void _updateCount({int horizontal=0, int vertical=0}) { 54 | setState(() { 55 | if (widget.state.viewModel.horizontalControlCount + horizontal > 0 && 56 | widget.state.viewModel.horizontalControlCount + horizontal < 25) { 57 | widget.state.viewModel.horizontalControlCount += horizontal; 58 | } 59 | if (widget.state.viewModel.verticalControlCount + vertical > 0 && 60 | widget.state.viewModel.verticalControlCount + vertical < 25) { 61 | widget.state.viewModel.verticalControlCount += vertical; 62 | } 63 | }); 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/newScreenWizard/newScreenWizardGeneral.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/backend/models/intl/intlNewScreenWizard.dart'; 3 | import 'package:gic_flutter/src/theme/dimensions.dart' as dim; 4 | 5 | import 'layoutWidget.dart'; 6 | import 'orientationWidget.dart'; 7 | import 'newScreenWizard.dart'; 8 | 9 | class NewScreenWizardGeneral extends StatefulWidget { 10 | final NewScreenWizardState state; 11 | 12 | const NewScreenWizardGeneral (this.state, { Key? key }): super(key: key); 13 | 14 | @override 15 | State createState() { 16 | state.screenNameTextController.addListener(() { state.viewModel.screenName = state.screenNameTextController.text;}); 17 | return NewScreenWizardGeneralState(); 18 | } 19 | } 20 | 21 | class NewScreenWizardGeneralState extends State { 22 | @override 23 | Widget build(BuildContext context) { 24 | return SingleChildScrollView( 25 | child: Padding( 26 | padding: EdgeInsets.all(dim.activityMargin), 27 | child: Column( 28 | children: [ 29 | TextField( 30 | controller: widget.state.screenNameTextController, 31 | decoration: InputDecoration( 32 | hintText: widget.state.translation.text(NewScreenWizardText.screenName)), 33 | 34 | ), 35 | OrientationWidget(widget.state), 36 | LayoutWidget(widget.state), 37 | //ControlDesignWidget(widget.state), 38 | ], 39 | ), 40 | ), 41 | ); 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/options/optionsPresentation.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:gic_flutter/src/backend/models/intl/intlOptions.dart'; 3 | import 'package:gic_flutter/src/backend/models/intl/localizations.dart'; 4 | import 'package:gic_flutter/src/backend/models/launcherModel.dart'; 5 | import 'package:gic_flutter/src/backend/repositories/launcherRepository.dart'; 6 | import 'package:gic_flutter/src/views/basePage.dart'; 7 | 8 | import 'optionsVM.dart'; 9 | 10 | class OptionsPresentation implements BasePresentation { 11 | BaseState _contract; 12 | LauncherRepository _repository = LauncherRepository(); 13 | OptionsVM? _viewModel; 14 | 15 | OptionsPresentation(this._contract); 16 | 17 | Future buildVM(BuildContext context) async { 18 | _viewModel = OptionsVM(); 19 | _viewModel!.toolbarTitle = 20 | Intl.of(context)!.options(OptionsText.toolbarTitle); 21 | _viewModel!.darkModeTitle = 22 | Intl.of(context)!.options(OptionsText.darkModeTitle); 23 | _viewModel!.darkModelText = 24 | Intl.of(context)!.options(OptionsText.darkModeText); 25 | _viewModel!.soundTitle = Intl.of(context)!.options(OptionsText.soundTitle); 26 | _viewModel!.soundText = Intl.of(context)!.options(OptionsText.soundText); 27 | _viewModel!.vibrationTitle = 28 | Intl.of(context)!.options(OptionsText.vibrationTitle); 29 | _viewModel!.vibrationText = 30 | Intl.of(context)!.options(OptionsText.vibrationText); 31 | _viewModel!.keepScreenOnTitle = 32 | Intl.of(context)!.options(OptionsText.keepScreenOnTitle); 33 | _viewModel!.keepScreenOnText = 34 | Intl.of(context)!.options(OptionsText.keepScreenOnText); 35 | await _fetchAllPreferences(); 36 | _contract.onLoadComplete(_viewModel!); 37 | } 38 | 39 | void setTheme(bool isDarkMode) { 40 | _repository.setDarkMode(isDarkMode); 41 | _viewModel!.darkMode = isDarkMode; 42 | _contract.onLoadComplete(_viewModel!); 43 | } 44 | 45 | void setVibration(bool hapticsEnabled) { 46 | _repository.setVibration(hapticsEnabled); 47 | _viewModel!.vibration = hapticsEnabled; 48 | _contract.onLoadComplete(_viewModel!); 49 | } 50 | 51 | void setSound(bool soundEnabled) { 52 | _repository.setSound(soundEnabled); 53 | _viewModel!.sound = soundEnabled; 54 | _contract.onLoadComplete(_viewModel!); 55 | } 56 | 57 | void setScreenOn(bool keepScreenOn) { 58 | _repository.setScreenOn(keepScreenOn); 59 | _viewModel!.keepScreenOn = keepScreenOn; 60 | _contract.onLoadComplete(_viewModel!); 61 | } 62 | 63 | Future _fetchAllPreferences() async { 64 | LauncherModel itemModel = await _repository.fetch(); 65 | _viewModel!.darkMode = itemModel.darkMode; 66 | _viewModel!.vibration = itemModel.vibration; 67 | _viewModel!.sound = itemModel.sound; 68 | _viewModel!.keepScreenOn = itemModel.keepScreenOn; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/options/optionsVM.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | import 'package:gic_flutter/src/backend/models/viewModel.dart'; 4 | 5 | class OptionsVM implements ViewModel { 6 | String _toolbarTitle = ""; 7 | String darkModeTitle = ""; 8 | String darkModelText = ""; 9 | String _soundTitle = ""; 10 | String _soundText = ""; 11 | String _vibrationTitle = ""; 12 | String _vibrationText = ""; 13 | String _keepScreenOnTitle = ""; 14 | String _keepScreenOnText = ""; 15 | 16 | bool _sound = false; 17 | bool _haptics = false; 18 | bool _darkMode = true; 19 | bool _keepScreenOn = false; 20 | 21 | String get toolbarTitle => _toolbarTitle; 22 | String get soundTitle => _soundTitle; 23 | String get soundText => _soundText; 24 | String get vibrationTitle => _vibrationTitle; 25 | String get vibrationText => _vibrationText; 26 | String get keepScreenOnTitle => _keepScreenOnTitle; 27 | String get keepScreenOnText => _keepScreenOnText; 28 | 29 | bool get darkMode => _darkMode; 30 | bool get vibration => _haptics; 31 | bool get sound => _sound; 32 | bool get keepScreenOn => _keepScreenOn; 33 | 34 | set toolbarTitle(String toolbarTitle) { 35 | _toolbarTitle = toolbarTitle; 36 | } 37 | 38 | set darkMode(bool darkTheme) { 39 | _darkMode = darkTheme; 40 | } 41 | 42 | set vibration(bool haptics) { 43 | _haptics = haptics; 44 | } 45 | 46 | set sound(bool sound) { 47 | _sound = sound; 48 | } 49 | 50 | set keepScreenOn(bool keepScreenOn) { 51 | _keepScreenOn = keepScreenOn; 52 | } 53 | 54 | set soundTitle(String soundTitle) { 55 | _soundTitle = soundTitle; 56 | } 57 | 58 | set soundText(String soundText) { 59 | _soundText = soundText; 60 | } 61 | 62 | set vibrationTitle(String vibrationTitle) { 63 | _vibrationTitle = vibrationTitle; 64 | } 65 | 66 | set vibrationText(String vibrationText) { 67 | _vibrationText = vibrationText; 68 | } 69 | 70 | set keepScreenOnTitle(String keepScreenOnTitle) { 71 | _keepScreenOnTitle = keepScreenOnTitle; 72 | } 73 | 74 | set keepScreenOnText(String keepScreenOnText) { 75 | _keepScreenOnText = keepScreenOnText; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screen/gicControl.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/backend/models/networkModel.dart'; 3 | import 'package:gic_flutter/src/views/baseGicControl.dart'; 4 | import 'package:gic_flutter/src/views/screen/screenView.dart'; 5 | 6 | class GicControl extends BaseGicControl { 7 | final NetworkModel? networkModel; 8 | final BoxConstraints? constraints; 9 | final ScreenView? screenView; 10 | 11 | GicControl( 12 | { 13 | Key? key, 14 | required control, 15 | required this.networkModel, 16 | required pixelRatio, 17 | this.screenView, 18 | this.constraints 19 | }) 20 | : super( 21 | key: key, 22 | control: control, 23 | pixelRatio: pixelRatio, 24 | constraints: constraints); 25 | 26 | @override 27 | State createState() { 28 | return GicButtonState( 29 | control: control, 30 | networkModel: networkModel, 31 | pixelRatio: pixelRatio, 32 | constraints: constraints); 33 | } 34 | } 35 | 36 | class GicButtonState extends BaseGicControlState { 37 | final NetworkModel? networkModel; 38 | final BoxConstraints? constraints; 39 | 40 | GicButtonState( 41 | {required control, 42 | required this.networkModel, 43 | required pixelRatio, 44 | required this.constraints}) 45 | : super(control: control, pixelRatio: pixelRatio); 46 | 47 | void sendCommand(String? commandUrl, int commandIndex, bool provideFeedback) { 48 | if ((widget as GicControl).screenView != null) 49 | (widget as GicControl).screenView!.sendCommand(control, commandUrl!, context, commandIndex, provideFeedback).ignore(); 50 | } 51 | 52 | GestureDetector buildControl() { 53 | return GestureDetector( 54 | onTapDown: (TapDownDetails details) => onTap(), 55 | onTapUp: (TapUpDetails details) => onTapUp(), 56 | child: buildControlContainer(constraints)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screen/screenVM.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | import 'package:gic_flutter/src/backend/models/networkModel.dart'; 4 | import 'package:gic_flutter/src/backend/models/screen/viewModels/screenViewModel.dart'; 5 | import 'package:gic_flutter/src/backend/models/viewModel.dart'; 6 | 7 | class ScreenVM implements ViewModel { 8 | final ScreenViewModel screen; 9 | final NetworkModel networkModel; 10 | final bool playSound; 11 | final bool vibration; 12 | final bool keepScreenOn; 13 | 14 | ScreenVM(this.screen, this.networkModel, this.playSound, this.vibration, 15 | this.keepScreenOn); 16 | 17 | @override 18 | // TODO: implement toolbarTitle 19 | String get toolbarTitle => throw UnimplementedError(); 20 | } 21 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screen/screenView.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:audioplayers/audioplayers.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/services.dart'; 6 | import 'package:gic_flutter/src/backend/models/screen/viewModels/controlViewModel.dart'; 7 | import 'package:gic_flutter/src/backend/services/networkService.dart'; 8 | import 'package:gic_flutter/src/views/screen/screenVM.dart'; 9 | import 'package:keep_screen_on/keep_screen_on.dart'; 10 | 11 | import 'gicControl.dart'; 12 | 13 | /// Wrapper for stateful functionality to provide onInit calls in our stateless 14 | /// screenview widget 15 | class ScreenViewStatefulWrapper extends StatefulWidget { 16 | final ScreenVM viewModel; 17 | 18 | const ScreenViewStatefulWrapper({required this.viewModel}); 19 | @override 20 | _StatefulWrapperState createState() => _StatefulWrapperState(this.viewModel); 21 | } 22 | 23 | class _StatefulWrapperState extends State { 24 | final ScreenVM viewModel; 25 | 26 | _StatefulWrapperState(this.viewModel); 27 | 28 | @override 29 | void initState() { 30 | super.initState(); 31 | SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); 32 | } 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return ScreenView(screenVM: viewModel); 37 | } 38 | 39 | @override 40 | void dispose() { 41 | super.dispose(); 42 | KeepScreenOn.turnOff(); 43 | } 44 | } 45 | 46 | class ScreenView extends StatelessWidget { 47 | final List widgets = []; 48 | final ScreenVM screenVM; 49 | final AudioPlayer player = new AudioPlayer(); 50 | final alarmAudioPath = "audio/flick.wav"; 51 | 52 | ScreenView({Key? key, required this.screenVM}); 53 | 54 | @override 55 | Widget build(BuildContext context) { 56 | double pixelRatio = MediaQuery.of(context).devicePixelRatio; 57 | screenVM.screen.controls!.forEach((element) { 58 | widgets.add(_buildGicControl(element, pixelRatio)); 59 | }); 60 | if (screenVM.keepScreenOn) { 61 | KeepScreenOn.turnOn(); 62 | } 63 | 64 | if (screenVM.screen.backgroundPath != null && 65 | screenVM.screen.backgroundPath!.isNotEmpty) { 66 | imageCache.clear(); 67 | imageCache.clearLiveImages(); 68 | 69 | return Scaffold( 70 | body: Container( 71 | decoration: BoxDecoration( 72 | image: DecorationImage( 73 | image: FileImage(File(screenVM.screen.backgroundPath!)), 74 | fit: BoxFit.fill, 75 | ), 76 | ), 77 | child: Stack(children: widgets), 78 | ), 79 | ); 80 | } else { 81 | return Scaffold( 82 | body: Container( 83 | color: screenVM.screen.backgroundColor, 84 | child: Stack(children: widgets), 85 | ), 86 | ); 87 | } 88 | } 89 | 90 | Widget _buildGicControl(ControlViewModel element, double pixelRatio) { 91 | return Positioned( 92 | left: element.left / pixelRatio, 93 | top: element.top / pixelRatio, 94 | child: GicControl( 95 | control: element, 96 | networkModel: screenVM.networkModel, 97 | screenView: this, 98 | pixelRatio: pixelRatio)); 99 | } 100 | 101 | Future sendCommand(ControlViewModel control, String commandUrl, BuildContext context, 102 | int commandIndex, bool provideFeedback) async { 103 | if (provideFeedback) { 104 | playSound(); 105 | vibration(); 106 | } 107 | NetworkResponse response = await NetworkService.sendCommand( 108 | screenVM.networkModel, commandUrl, control.commands[commandIndex]); 109 | if (response == NetworkResponse.Error) { 110 | var snackBar = SnackBar(content: Text("Error Connecting to Server")); 111 | ScaffoldMessenger.of(context).showSnackBar(snackBar); 112 | } else if (response == NetworkResponse.Unauthorized) { 113 | var snackBar = SnackBar(content: Text("Unauthorized, check that the passwords match")); 114 | ScaffoldMessenger.of(context).showSnackBar(snackBar); 115 | } 116 | } 117 | 118 | void playSound() { 119 | if (screenVM.playSound) { 120 | player.play(AssetSource(alarmAudioPath)); 121 | } 122 | } 123 | 124 | void vibration() { 125 | if (screenVM.vibration) { 126 | HapticFeedback.lightImpact().ignore(); 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screenEditor/backgroundDialog.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:file_picker/file_picker.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:gic_flutter/src/backend/models/intl/intlScreenEditor.dart'; 6 | import 'package:gic_flutter/src/backend/models/screen/viewModels/screenViewModel.dart'; 7 | import 'package:gic_flutter/src/views/screenEditor/colorPickerDialog.dart'; 8 | import 'package:gic_flutter/src/views/screenEditor/settingsDialog/dialogButton.dart'; 9 | import 'package:path/path.dart' as path; 10 | import 'package:path_provider/path_provider.dart'; 11 | 12 | class BackgroundDialog extends StatefulWidget { 13 | final IntlScreenEditor? translation; 14 | final ScreenViewModel? screenViewModel; 15 | 16 | const BackgroundDialog({Key? key, this.translation, this.screenViewModel}) 17 | : super(key: key); 18 | 19 | @override 20 | _BackgroundDialogState createState() => 21 | _BackgroundDialogState(translation!, screenViewModel!); 22 | } 23 | 24 | class _BackgroundDialogState extends State { 25 | IntlScreenEditor translation; 26 | ScreenViewModel screenViewModel; 27 | 28 | _BackgroundDialogState(this.translation, this.screenViewModel); 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return SimpleDialog( 33 | title: Text(translation.text(ScreenEditorText.backgroundMenu)), 34 | children: [ 35 | DialogButton( 36 | icon: Icons.image, 37 | color: Colors.blue, 38 | text: translation.text(ScreenEditorText.backgroundImage), 39 | onPressed: () { 40 | _pickBackgroundImage(); 41 | }), 42 | DialogButton( 43 | icon: Icons.color_lens, 44 | color: Colors.green, 45 | text: translation.text(ScreenEditorText.backgroundColor), 46 | onPressed: () { 47 | _pickBackgroundColor(); 48 | }, 49 | ), 50 | ], 51 | ); 52 | } 53 | 54 | void _pickBackgroundImage() async { 55 | await FilePicker.platform.clearTemporaryFiles(); 56 | FilePickerResult? result = await FilePicker.platform.pickFiles( 57 | type: FileType.custom, 58 | allowedExtensions: ['jpg', 'png', 'gif'], 59 | ); 60 | if (result != null) { 61 | imageCache.clear(); 62 | imageCache.clearLiveImages(); 63 | 64 | PlatformFile file = result.files.first; 65 | Directory dest = await getApplicationDocumentsDirectory(); 66 | String destPath = path.join( 67 | dest.path, "screens", screenViewModel.screenId.toString(), path.basename(file.path!)); 68 | if (screenViewModel.backgroundPath != null && File(screenViewModel.backgroundPath!).existsSync()) 69 | File(screenViewModel.backgroundPath!).deleteSync(); 70 | File newFile = File(file.path!).copySync(destPath); 71 | setState(() { 72 | screenViewModel.backgroundPath = newFile.path; 73 | 74 | Navigator.pop(context, true); 75 | }); 76 | } 77 | } 78 | 79 | void _pickedColor(Color color) { 80 | screenViewModel.backgroundColor = color.withAlpha(255); 81 | screenViewModel.backgroundPath = ""; 82 | Navigator.pop(context); 83 | } 84 | 85 | void _pickBackgroundColor() { 86 | showDialog( 87 | context: context, 88 | builder: (_) => ColorPickerDialog( 89 | title: translation.text(ScreenEditorText.backgroundColor), 90 | pickerColor: screenViewModel.backgroundColor, 91 | onPressedCallback: _pickedColor, 92 | )); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screenEditor/colorPickerDialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_colorpicker/flutter_colorpicker.dart'; 3 | 4 | class ColorDialog { 5 | static Color? pickerColor; 6 | 7 | static show(BuildContext context, changeColorCallback, onPressedCallback) { 8 | return showDialog( 9 | context: context, 10 | builder: (BuildContext context) { 11 | return AlertDialog( 12 | title: const Text('Pick a color!'), 13 | content: SingleChildScrollView( 14 | child: ColorPicker( 15 | pickerColor: pickerColor!, 16 | onColorChanged: changeColorCallback, 17 | showLabel: true, 18 | pickerAreaHeightPercent: 0.8, 19 | ), 20 | ), 21 | actions: [ 22 | TextButton( 23 | child: const Text('Got it'), 24 | onPressed: onPressedCallback, 25 | ), 26 | ], 27 | ); 28 | }, 29 | ); 30 | } 31 | } 32 | 33 | class ColorPickerDialog extends StatefulWidget { 34 | final Function(Color color)? onPressedCallback; 35 | final String? title; 36 | final Color? pickerColor; 37 | 38 | const ColorPickerDialog( 39 | {Key? key, this.title, this.onPressedCallback, this.pickerColor}) 40 | : super(key: key); 41 | 42 | @override 43 | _ColorPickerDialogState createState() => _ColorPickerDialogState(pickerColor!); 44 | } 45 | 46 | class _ColorPickerDialogState extends State { 47 | Color pickerColor; 48 | 49 | _ColorPickerDialogState(this.pickerColor) { 50 | 51 | } 52 | 53 | @override 54 | Widget build(BuildContext context) { 55 | return AlertDialog( 56 | title: Text(widget.title!), 57 | content: SingleChildScrollView( 58 | child: ColorPicker( 59 | pickerColor: pickerColor, 60 | onColorChanged: (Color color) { 61 | setState(() => pickerColor = color); 62 | }, 63 | showLabel: true, 64 | enableAlpha: false, 65 | )), 66 | actions: [ 67 | TextButton( 68 | child: Text("OK"), 69 | onPressed: () { 70 | widget.onPressedCallback!(pickerColor); 71 | Navigator.pop(context); 72 | }), 73 | ], 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screenEditor/controlDialog/baseTab.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/backend/models/intl/intlScreenEditor.dart'; 3 | import 'package:gic_flutter/src/backend/models/screen/controlDefaults.dart'; 4 | import 'package:gic_flutter/src/views/screen/gicControl.dart'; 5 | import 'package:gic_flutter/src/views/screenEditor/gicEditControl.dart'; 6 | 7 | abstract class BaseTab extends StatefulWidget { 8 | final IntlScreenEditor translation; 9 | final GicEditControl gicEditControl; 10 | final int? screenId; 11 | final ControlDefaults? defaultControls; 12 | 13 | BaseTab({Key? key, required this.gicEditControl, required this.translation, required this.screenId, this.defaultControls}) 14 | : super(key: key); 15 | } 16 | 17 | abstract class BaseTabState extends State { 18 | @protected 19 | double pixelRatio = 1; 20 | 21 | @protected 22 | Widget preview([BoxConstraints? constraints]) { 23 | return Column( 24 | children: [ 25 | Padding( 26 | padding: const EdgeInsets.all(16.0), 27 | child: Text(widget.translation.text(ScreenEditorText.previewHeader), 28 | style: Theme.of(context).textTheme.headlineSmall), 29 | ), 30 | FittedBox( 31 | child: GicControl( 32 | constraints: constraints!, 33 | pixelRatio: pixelRatio, 34 | control: widget.gicEditControl.control, 35 | networkModel: null, 36 | ), 37 | ), 38 | ], 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screenEditor/controlDialog/imageDialog.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/services.dart'; 6 | import 'package:path_provider/path_provider.dart'; 7 | import 'package:path/path.dart' as path; 8 | 9 | class ImageDialog extends StatefulWidget { 10 | @override 11 | _ImageDialogState createState() => _ImageDialogState(); 12 | } 13 | 14 | class _ImageDialogState extends State { 15 | _ImageDialogState(); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Scaffold( 20 | body: CustomScrollView( 21 | slivers: [ 22 | SliverAppBar( 23 | title: Text('Pick Image'), 24 | ), 25 | _ImageList(), 26 | ], 27 | ), 28 | ); 29 | } 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | _ImageServer.loadImages().then((value) => setState(() {})); 35 | } 36 | } 37 | 38 | class _ImageList extends StatelessWidget { 39 | _ImageList(); 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | return SliverList( 44 | delegate: SliverChildBuilderDelegate( 45 | (BuildContext context, int index) { 46 | return Material( 47 | child: InkWell( 48 | onTap: () { 49 | Navigator.pop(context, _ImageServer.getFilenameByIndex(index)); 50 | }, 51 | child: Container( 52 | child: ClipRRect( 53 | child: _ImageServer.getImageByIndex(index), 54 | ), 55 | ), 56 | )); 57 | }, 58 | childCount: _ImageServer.length(), 59 | ), 60 | ); 61 | } 62 | } 63 | 64 | /// this class handles the loading of custom and built in images 65 | class _ImageServer { 66 | static List? _images; 67 | static List? _imagePaths; 68 | 69 | static Widget getImageByIndex(int index) { 70 | return _images![index]; 71 | } 72 | 73 | static getFilenameByIndex(int index) { 74 | return _imagePaths![index]; 75 | } 76 | static int length() => _images!.length; 77 | 78 | static Future loadImages() async { 79 | _images = []; 80 | _imagePaths = []; 81 | //first we load in any custom images 82 | Directory filesDir = await getApplicationSupportDirectory(); 83 | await filesDir.list(recursive: false).forEach((element) { 84 | if (element.path.contains("button_")) { 85 | //valid image 86 | _images!.add(Image.file(File(element.path), width: 120.0, height: 80.0)); 87 | _imagePaths!.add(element.path); 88 | } 89 | }); 90 | 91 | //now load in the defaults 92 | final manifestContent = await rootBundle.loadString('AssetManifest.json'); 93 | final Map manifestMap = json.decode(manifestContent); 94 | manifestMap.keys.where((String key) => key.contains('images/controls/')).forEach((element) { 95 | _images!.add(Image(image:AssetImage(element), 96 | width: 120.0, height: 80.0)); 97 | File file = File(element); 98 | String basename = path.basenameWithoutExtension(file.path); 99 | _imagePaths!.add(basename); 100 | }); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screenEditor/gicEditControl.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gesture_x_detector/gesture_x_detector.dart'; 3 | import 'package:gic_flutter/src/views/baseGicControl.dart'; 4 | 5 | typedef void SelectedWidgetCallback(int selectedControlIndex); 6 | typedef void DragControl( 7 | double newLeft, double newTop, int selectedControlIndex); 8 | 9 | class GicEditControl extends BaseGicControl { 10 | final SelectedWidgetCallback? onSelected; 11 | final int controlIndex; 12 | final GridSize gridSize; 13 | final bool disableDrag; 14 | 15 | GicEditControl( 16 | {Key? key, 17 | required this.gridSize, 18 | required this.disableDrag, 19 | @required control, 20 | required this.controlIndex, 21 | required this.onSelected, 22 | @required pixelRatio}) 23 | : super( 24 | key: key, 25 | control: control, 26 | pixelRatio: pixelRatio, 27 | constraints: null); 28 | 29 | @override 30 | State createState() { 31 | return GicEditControlState( 32 | disableDrag: disableDrag, 33 | gridSize: gridSize, 34 | control: control, 35 | controlIndex: controlIndex, 36 | onSelected: onSelected, 37 | pixelRatio: pixelRatio); 38 | } 39 | } 40 | 41 | class GicEditControlState extends BaseGicControlState { 42 | final SelectedWidgetCallback? onSelected; 43 | final int controlIndex; 44 | final bool disableDrag; 45 | final GridSize gridSize; 46 | 47 | double _originalWidth = 0; 48 | double _originalHeight = 0; 49 | 50 | GicEditControlState( 51 | {required this.gridSize, 52 | required this.disableDrag, 53 | @required control, 54 | required this.controlIndex, 55 | required this.onSelected, 56 | @required pixelRatio}) 57 | : super(control: control, pixelRatio: pixelRatio) { 58 | _originalWidth = control.width; 59 | _originalHeight = control.height; 60 | } 61 | 62 | Widget buildControl() { 63 | if (disableDrag) { 64 | return Positioned( 65 | top: control.top / pixelRatio, 66 | left: control.left / pixelRatio, 67 | child: XGestureDetector( 68 | onTap: onLongPress, 69 | bypassTapEventOnDoubleTap: false, 70 | child: buildControlContainer()), 71 | ); 72 | } 73 | return Positioned( 74 | top: control.top / pixelRatio, 75 | left: control.left / pixelRatio, 76 | child: XGestureDetector( 77 | longPressTimeConsider: 200, 78 | onLongPress: onLongPress, 79 | onMoveUpdate: onMoveUpdate, 80 | onScaleUpdate: onScaleUpdate, 81 | onScaleEnd: onScaleEnd, 82 | bypassTapEventOnDoubleTap: false, 83 | child: buildControlContainer()), 84 | ); 85 | } 86 | 87 | void onLongPress(event) { 88 | onSelected!(controlIndex); 89 | } 90 | 91 | void onScaleUpdate(ScaleEvent event) { 92 | setState(() { 93 | if (event.focalPoint.dx < 0) { 94 | control.width = (_originalWidth / event.scale).roundToDouble(); 95 | } else { 96 | control.width = (_originalWidth * event.scale).roundToDouble(); 97 | } 98 | if (event.focalPoint.dy < 0) { 99 | control.height = (_originalHeight / event.scale).roundToDouble(); 100 | } else { 101 | control.height = (_originalHeight * event.scale).roundToDouble(); 102 | } 103 | }); 104 | } 105 | 106 | void onScaleEnd() { 107 | _originalHeight = control.height; 108 | _originalWidth = control.width; 109 | } 110 | 111 | void onMoveUpdate(MoveEvent event) { 112 | setState(() { 113 | double adjustedX = _getGridPosition(startPosition: event.position.dx, size: control.width); 114 | double adjustedY = _getGridPosition(startPosition: event.position.dy, size: control.height); 115 | control.left = adjustedX; 116 | control.top = adjustedY; 117 | }); 118 | } 119 | 120 | sendCommand(String? commandUrl, int commandIndex, bool provideFeedback) { 121 | setState(() { 122 | onSelected!(controlIndex); 123 | }); 124 | } 125 | 126 | /// Determines where to place something, based on the currently set grid value 127 | /// startPosition - the raw position, either X or Y based 128 | /// size - size of the control, on the same axis as startPosition. -1 ignores 129 | double _getGridPosition({double? startPosition, double size = -1}) { 130 | double rawPos = startPosition! * pixelRatio; 131 | if (size > -1) { 132 | rawPos = rawPos - (size / 2); 133 | } 134 | int adjustedSize = gridSize.value; 135 | if (gridSize.value < 1) { 136 | adjustedSize = 1; 137 | } 138 | int gridPos = (rawPos.round() / adjustedSize).round(); 139 | return gridPos * adjustedSize.toDouble(); 140 | } 141 | 142 | } 143 | 144 | class GridSize { 145 | int _value = 0; 146 | 147 | int get value { 148 | return _value; 149 | } 150 | 151 | void set value(int newValue) { 152 | _value = newValue; 153 | } 154 | } -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screenEditor/helpDialog/helpDialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/backend/models/intl/intlScreenEditor.dart'; 3 | import 'package:gic_flutter/src/views/screenEditor/helpDialog/selectTab.dart'; 4 | 5 | class HelpDialog extends StatefulWidget { 6 | final IntlScreenEditor translation; 7 | 8 | HelpDialog({Key? key, required this.translation}) 9 | : super(key: key); 10 | 11 | @override 12 | _HelpDialogState createState() => _HelpDialogState(translation); 13 | } 14 | 15 | class _HelpDialogState extends State { 16 | final IntlScreenEditor translation; 17 | 18 | List _tabs = []; 19 | List _tabContents = []; 20 | 21 | _HelpDialogState(this.translation); 22 | 23 | //headers 24 | Widget editTab() => Tab(icon: Icon(Icons.edit)); 25 | Widget movingTab() => Tab(icon: Icon(Icons.touch_app)); 26 | Widget sizingTab() => Tab(icon: Icon(Icons.photo_size_select_large)); 27 | Widget quitTab() => Tab(icon: Icon(Icons.exit_to_app)); 28 | 29 | @override 30 | void initState() { 31 | super.initState(); 32 | } 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | buildTabs(); 37 | return Dialog( 38 | child: DefaultTabController( 39 | length: _tabs.length, 40 | child: Scaffold( 41 | appBar: AppBar( 42 | title: 43 | Text(translation.text(ScreenEditorText.helpDialogTitle)), 44 | bottom: TabBar( 45 | tabs: _tabs, 46 | ), 47 | ), 48 | body: Padding( 49 | padding: const EdgeInsets.all(16.0), 50 | child: TabBarView( 51 | children: _tabContents, 52 | ), 53 | ), 54 | ))); 55 | } 56 | 57 | //sets up the tabs, based on type of control we're editing 58 | //different control types need different tab views 59 | void buildTabs() { 60 | _tabs = []; 61 | _tabContents = []; 62 | _tabs.add(editTab()); 63 | _tabContents.add(SimpleTextTab( 64 | title: translation.text(ScreenEditorText.helpEditHeader), 65 | details: translation.text(ScreenEditorText.helpEditDetails), 66 | )); 67 | _tabs.add(movingTab()); 68 | _tabContents.add(SimpleTextTab( 69 | title: translation.text(ScreenEditorText.helpMoveHeader), 70 | details: translation.text(ScreenEditorText.helpMoveDetails), 71 | )); 72 | _tabs.add(sizingTab()); 73 | _tabContents.add(SimpleTextTab( 74 | title: translation.text(ScreenEditorText.helpSizeHeader), 75 | details: translation.text(ScreenEditorText.helpSizeDetails), 76 | )); 77 | _tabs.add(quitTab()); 78 | _tabContents.add(SimpleTextTab( 79 | title: translation.text(ScreenEditorText.helpQuitHeader), 80 | details: translation.text(ScreenEditorText.helpQuitDetails), 81 | )); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screenEditor/helpDialog/selectTab.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// This class shows a very simple tab containing a title and details below it. 4 | class SimpleTextTab extends StatefulWidget { 5 | final String title; 6 | final String details; 7 | 8 | SimpleTextTab({Key? key, required this.title, required this.details}) : super(key: key); 9 | 10 | @override 11 | _SimpleTextTabState createState() => _SimpleTextTabState(); 12 | } 13 | 14 | class _SimpleTextTabState extends State { 15 | @override 16 | Widget build(BuildContext context) { 17 | return Container( 18 | child: LayoutBuilder( 19 | builder: (BuildContext ctx, BoxConstraints constraints) { 20 | return Column( 21 | children: [ 22 | Text(widget.title, 23 | style: Theme.of(context).textTheme.headlineSmall), 24 | Divider( 25 | height: 10, 26 | thickness: 2, 27 | ), 28 | Text(widget.details, textScaleFactor: 1.2,) 29 | ], 30 | ); 31 | }), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screenEditor/settingsDialog/dialogButton.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DialogButton extends StatelessWidget { 4 | const DialogButton( 5 | {Key? key, required this.icon, required this.color, required this.text, required this.onPressed}) 6 | : super(key: key); 7 | 8 | final IconData icon; 9 | final Color color; 10 | final String text; 11 | final VoidCallback onPressed; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return SimpleDialogOption( 16 | onPressed: onPressed, 17 | child: Row( 18 | mainAxisAlignment: MainAxisAlignment.start, 19 | crossAxisAlignment: CrossAxisAlignment.center, 20 | children: [ 21 | Icon(icon, size: 36.0, color: color), 22 | Padding( 23 | padding: const EdgeInsetsDirectional.only(start: 16.0), 24 | child: Text(text), 25 | ), 26 | ], 27 | ), 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screenEditor/settingsDialog/dialogSlider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DialogSlider extends StatefulWidget { 4 | DialogSlider( 5 | {Key? key, 6 | required this.icon, 7 | required this.color, 8 | required this.text, 9 | required this.onChanged, 10 | required this.originalValue}) 11 | : super(key: key); 12 | 13 | final IconData icon; 14 | final Color color; 15 | final String text; 16 | final int originalValue; 17 | final void Function(double updated) onChanged; 18 | 19 | @override 20 | _DialogSliderState createState() => _DialogSliderState(); 21 | } 22 | 23 | class _DialogSliderState extends State { 24 | late double _value; 25 | 26 | @override 27 | void initState() { 28 | super.initState(); 29 | _value = widget.originalValue.toDouble(); 30 | } 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | return Column( 35 | children: [ 36 | SimpleDialogOption( 37 | child: Row( 38 | mainAxisAlignment: MainAxisAlignment.start, 39 | crossAxisAlignment: CrossAxisAlignment.center, 40 | children: [ 41 | Icon(widget.icon, size: 36.0, color: widget.color), 42 | Padding( 43 | padding: const EdgeInsetsDirectional.only(start: 16.0), 44 | child: Text(widget.text), 45 | ), 46 | ], 47 | ), 48 | ), 49 | Slider( 50 | min: 0, 51 | max: 256, 52 | divisions: 8, 53 | value: _value, 54 | onChanged: (double newValue) { 55 | setState(() { 56 | _value = newValue; 57 | }); 58 | widget.onChanged(newValue); 59 | }), 60 | ], 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /gic_flutter/lib/src/views/screenEditor/settingsDialog/settingsDialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:gic_flutter/src/backend/models/intl/intlScreenEditor.dart'; 3 | import 'package:gic_flutter/src/backend/models/screen/viewModels/controlViewModel.dart'; 4 | import 'package:gic_flutter/src/views/screenEditor/screenEditor.dart'; 5 | import 'package:gic_flutter/src/views/screenEditor/settingsDialog/dialogButton.dart'; 6 | import 'package:gic_flutter/src/views/screenEditor/settingsDialog/dialogSlider.dart'; 7 | 8 | class SettingsDialog { 9 | static Widget display( 10 | BuildContext context, ScreenEditorState screenEditorState) { 11 | IntlScreenEditor translation = IntlScreenEditor(context); 12 | 13 | return SimpleDialog( 14 | title: Text(translation.text(ScreenEditorText.menu)), 15 | elevation: 5, 16 | children: [ 17 | DialogButton( 18 | icon: Icons.smart_button, 19 | color: Colors.orange, 20 | text: translation.text(ScreenEditorText.addButton), 21 | onPressed: () { 22 | screenEditorState.addControl(ControlViewModelType.Button); 23 | Navigator.pop(context, true); 24 | }, 25 | ), 26 | DialogButton( 27 | icon: Icons.toggle_off_outlined, 28 | color: Colors.green, 29 | text: translation.text(ScreenEditorText.addToggle), 30 | onPressed: () { 31 | screenEditorState.addControl(ControlViewModelType.Toggle); 32 | Navigator.pop(context, true); 33 | }, 34 | ), 35 | DialogButton( 36 | icon: Icons.text_fields, 37 | color: Colors.blue, 38 | text: translation.text(ScreenEditorText.addText), 39 | onPressed: () { 40 | screenEditorState.addControl(ControlViewModelType.Text); 41 | Navigator.pop(context, true); 42 | }, 43 | ), 44 | DialogButton( 45 | icon: Icons.image, 46 | color: Colors.red, 47 | text: translation.text(ScreenEditorText.addImage), 48 | onPressed: () { 49 | screenEditorState.addControl(ControlViewModelType.Image); 50 | Navigator.pop(context, true); 51 | }, 52 | ), 53 | Divider( 54 | height: 10, 55 | thickness: 5, 56 | indent: 20, 57 | endIndent: 20, 58 | ), 59 | DialogButton( 60 | icon: Icons.color_lens, 61 | color: Colors.yellow, 62 | text: translation.text(ScreenEditorText.setBackground), 63 | onPressed: () { 64 | screenEditorState.showBackgroundDialog(); 65 | }, 66 | ), 67 | DialogSlider( 68 | icon: Icons.grid_on, 69 | color: Colors.grey, 70 | text: translation.text(ScreenEditorText.setGrid), 71 | originalValue: screenEditorState.gridSize.value, 72 | onChanged: (double newValue) { 73 | screenEditorState.gridChangeListener(newValue); 74 | }, 75 | ), 76 | Divider( 77 | height: 10, 78 | thickness: 5, 79 | indent: 20, 80 | endIndent: 20, 81 | ), 82 | DialogButton( 83 | icon: Icons.save, 84 | color: Colors.tealAccent, 85 | text: translation.text(ScreenEditorText.save), 86 | onPressed: () { 87 | screenEditorState.tapSave(); 88 | Navigator.pop(context, true); 89 | }, 90 | ), 91 | DialogButton( 92 | icon: Icons.help, 93 | color: Colors.amber, 94 | text: translation.text(ScreenEditorText.helpDialogTitle), 95 | onPressed: () { 96 | screenEditorState.tapHelp(); 97 | }, 98 | ), 99 | DialogButton( 100 | icon: Icons.alt_route, 101 | color: Colors.red, 102 | text: translation.text(ScreenEditorText.altMode), 103 | onPressed: () { 104 | screenEditorState.tapAltMode(); 105 | }, 106 | ), 107 | ], 108 | ); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /gic_flutter/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: gic_flutter 2 | description: Gaming Interface Client 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 5.4.3+26030090 15 | 16 | environment: 17 | sdk: ">=3.5.0 <4.0.0" 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | flutter_localizations: 23 | sdk: flutter 24 | #flutter_cupertino_localizations: ^1.0.1 25 | 26 | # The following adds the Cupertino Icons font to your application. 27 | # Use with the CupertinoIcons class for iOS style icons. 28 | cupertino_icons: ^1.0.6 29 | 30 | archive: ^3.3.8 31 | audioplayers: ^6.1.0 32 | device_info_plus: ^10.1.2 33 | equatable: ^2.0.3 34 | file_picker: ^8.0.7 35 | flutter_colorpicker: ^1.0.3 36 | flutter_email_sender: ^6.0.3 37 | flutter_linkify: ^6.0.0 38 | get_it: ^8.0.2 39 | http: ^1.2.2 40 | introduction_screen: ^3.1.11 41 | keep_screen_on: ^3.0.0 42 | package_info_plus: ^8.1.1 43 | path_provider: ^2.1.1 44 | permission_handler: ^11.3.1 45 | pointycastle: ^3.7.3 46 | rxdart: ^0.28.0 47 | scrollable_positioned_list: ^0.3.8 48 | #nullable scrollable_positioned_list: ^0.2.0-nullsafety.0 49 | share_plus: ^10.0.0 50 | shared_preferences: ^2.2.1 #'>=0.5.7+3 <2.0.0' 51 | #nullable shared_preferences: ^2.0.6 52 | showcaseview: ^3.0.0 53 | url_launcher: ^6.1.14 54 | gesture_x_detector: 55 | path: ../xgesture_flutter 56 | 57 | #intent: ^1.3.4 58 | # For information on the generic Dart part of this file, see the 59 | # following page: https://www.dartlang.org/tools/pub/pubspec 60 | 61 | dependency_overrides: 62 | win32: ^5.5.4 63 | # The following section is specific to Flutter. 64 | flutter: 65 | 66 | # The following line ensures that the Material Icons font is 67 | # included with your application, so that you can use the icons in 68 | # the material Icons class. 69 | uses-material-design: true 70 | 71 | # To add assets to your application, add an assets section, like this: 72 | assets: 73 | - assets/screens/ 74 | - assets/images/icons/ 75 | - assets/images/controls/ 76 | - assets/audio/flick.wav 77 | 78 | # - images/a_dot_burr.jpeg 79 | # - images/a_dot_ham.jpeg 80 | 81 | # An image asset can refer to one or more resolution-specific "variants", see 82 | # https://flutter.dev/assets-and-images/#resolution-aware. 83 | 84 | # For details regarding adding assets from package dependencies, see 85 | # https://flutter.dev/assets-and-images/#from-packages 86 | 87 | # To add custom fonts to your application, add a fonts section here, 88 | # in this "flutter" section. Each entry in this list should have a 89 | # "family" key with the font family name, and a "fonts" key with a 90 | # list giving the asset and other descriptors for the font. For 91 | # example: 92 | fonts: 93 | - family: Lobster-Regular 94 | fonts: 95 | - asset: assets/fonts/Lobster-Regular.ttf 96 | - family: Nunito-Regular 97 | fonts: 98 | - asset: assets/fonts/Nunito-Regular.ttf 99 | - family: ShareTech-Regular 100 | fonts: 101 | - asset: assets/fonts/ShareTech-Regular.ttf 102 | - family: Righteous-Regular 103 | fonts: 104 | - asset: assets/fonts/Righteous-Regular.ttf 105 | # - family: Trajan Pro 106 | # fonts: 107 | # - asset: fonts/TrajanPro.ttf 108 | # - asset: fonts/TrajanPro_Bold.ttf 109 | # weight: 700 110 | # 111 | # For details regarding fonts from package dependencies, 112 | # see https://flutter.dev/custom-fonts/#from-packages 113 | -------------------------------------------------------------------------------- /gic_flutter/runbuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Choose your option" 3 | echo " 1) Build for Google Play" 4 | echo " 2) Build for Other" 5 | echo " 3) Run Google Play version" 6 | echo " 4) Run Other version" 7 | 8 | read n 9 | case $n in 10 | 1) flutter build appbundle -v -t lib/main_gplay.dart --flavor gplay;; 11 | 2) flutter build apk --split-per-abi -t lib/main_other.dart --flavor other --target-platform android-arm;; 12 | 3) flutter run --flavor gplay -v -t lib/main_gplay.dart;; 13 | 4) flutter run --flavor other -v -t lib/main_other.dart --target-platform android-arm;; 14 | *) echo "invalid option";; 15 | esac -------------------------------------------------------------------------------- /gic_flutter/runbuild.win.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Choose your option" 3 | echo " 1) Build for Google Play" 4 | echo " 2) Build for Other" 5 | echo " 3) Run Google Play version" 6 | echo " 4) Run Other version" 7 | 8 | read n 9 | case $n in 10 | 1) flutter build appbundle -v -t lib/main_gplay.dart --flavor gplay;; 11 | 2) flutter build apk --split-per-abi -t lib/main_other.dart --flavor other --target-platform android-arm;; 12 | 3) flutter run --flavor gplay -v -t lib/main_gplay.dart;; 13 | 4) flutter run --flavor other -v -t lib/main_other.dart --target-platform android-arm;; 14 | *) echo "invalid option";; 15 | esac -------------------------------------------------------------------------------- /release_notes.txt: -------------------------------------------------------------------------------- 1 | 4.5 alpha 2 | - Updated Network code for the new 2.0 Server 3 | - Shows a loading window while connecting to a server initially 4 | - Added Version check before launching a Screen 5 | -------------------------------------------------------------------------------- /xgesture_flutter/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: be9bc8cb3942bda5d8ef4e44b44616c470625e18 8 | channel: beta 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /xgesture_flutter/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.0.1] - TODO: Add release date. 2 | 3 | ## [0.0.2] - TODO: Update API document and example. 4 | 5 | ## [0.0.3] - TODO: dartfmt 6 | 7 | ## [0.0.4] 8 | 9 | ## [0.0.5] 10 | BREAKING 11 | * add new flag: bypassMoveEventAfterLongPress 12 | 13 | by default it is true, means after receive long press event without release pointer (finger still touch on screen the move event will be ignore. 14 | 15 | set it to false in case you expect move event will be fire after long press event 16 | 17 | * using parameter object instead of naked parameters 18 | 19 | old version 20 | ```dart 21 | @override 22 | Widget build(BuildContext context) { 23 | return XGestureDetector( 24 | child: Text("data"), 25 | onTap: (pointer, localPos, position) => print("localPos: $localPos, pointer: $pointer"), 26 | onScaleUpdate: (changedFocusPoint, scale, rotationAngle) => 27 | print("focalPoint: $changedFocusPoint, scale: $scale"), 28 | ); 29 | } 30 | ``` 31 | 32 | new version 33 | ``` 34 | Widget build(BuildContext context) { 35 | return XGestureDetector( 36 | child: Text("data"), 37 | onTap: (event) => 38 | print("localPos: ${event.localPos}, pointer: ${event.pointer}"), 39 | onScaleUpdate: (event) => 40 | print("focalPoint: ${event.focalPoint}, scale: ${event.scale}"), 41 | ); 42 | } 43 | ``` 44 | ## [1.0.0-nullsafety.0] 45 | BREAKING: opt into null safety 46 | feat!: upgrade Dart SDK constraints to >=2.12.0-0 <3.0.0 47 | 48 | ## [1.0.0-nullsafety.1] 49 | Support onLongPressEnd 50 | 51 | ## [1.0.0] 52 | sound null safety -------------------------------------------------------------------------------- /xgesture_flutter/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Viet Nguyen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /xgesture_flutter/README.md: -------------------------------------------------------------------------------- 1 | # gesture_x_detector 2 | 3 | A widget that detects gestures. 4 | 5 | Easy to use, lightweight gesture detector for Flutter apps. 6 | 7 | ## Features 8 | 9 | - Detect tap gestures (Tap, DoubleTap, Scale(start, update, end), Long press, Move(start, update, end) 10 | - All callbacks can be used simultaneously 11 | - Customize: ignore tap event on double tap, change duration time to detect double tap or long-press 12 | 13 | ## Getting Started 14 | 15 | ### Installation 16 | 17 | Add to pubspec.yaml: 18 | 19 | ```yaml 20 | dependencies: 21 | gesture_x_detector: 22 | ``` 23 | 24 | ### Example 25 | 26 | Checkout the example at https://github.com/taodo2291/xgesture_flutter/tree/master/example/lib/main.dart 27 | 28 | ```dart 29 | import 'package:flutter/material.dart'; 30 | import 'package:gesture_x_detector/gesture_x_detector.dart'; 31 | 32 | void main() { 33 | runApp( 34 | MaterialApp( 35 | home: XGestureExample(), 36 | ), 37 | ); 38 | } 39 | 40 | class XGestureExample extends StatefulWidget { 41 | @override 42 | _XGestureExampleState createState() => _XGestureExampleState(); 43 | } 44 | 45 | class _XGestureExampleState extends State { 46 | String lastEventName = 'Tap on screen'; 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return XGestureDetector( 51 | child: Material( 52 | child: Center( 53 | child: Text( 54 | lastEventName, 55 | style: TextStyle(fontSize: 30), 56 | ), 57 | ), 58 | ), 59 | doubleTapTimeConsider: 300, 60 | longPressTimeConsider: 350, 61 | onTap: onTap, 62 | onDoubleTap: onDoubleTap, 63 | onLongPress: onLongPress, 64 | onLongPressEnd: onLongPressEnd, 65 | onMoveStart: onMoveStart, 66 | onMoveEnd: onMoveEnd, 67 | onMoveUpdate: onMoveUpdate, 68 | onScaleStart: onScaleStart, 69 | onScaleUpdate: onScaleUpdate, 70 | onScaleEnd: onScaleEnd, 71 | bypassTapEventOnDoubleTap: false, 72 | ); 73 | } 74 | 75 | void onLongPressEnd() { 76 | setLastEventName('onLongPressEnd'); 77 | print('onLongPressEnd'); 78 | } 79 | 80 | void onScaleEnd() { 81 | setLastEventName('onScaleEnd'); 82 | print('onScaleEnd'); 83 | } 84 | 85 | void onScaleUpdate(ScaleEvent event) { 86 | setLastEventName('onScaleUpdate'); 87 | print( 88 | 'onScaleUpdate - changedFocusPoint: ${event.focalPoint} ; scale: ${event.scale} ;Rotation: ${event.rotationAngle}'); 89 | } 90 | 91 | void onScaleStart(initialFocusPoint) { 92 | setLastEventName('onScaleStart'); 93 | print('onScaleStart - initialFocusPoint: $initialFocusPoint'); 94 | } 95 | 96 | void onMoveUpdate(MoveEvent event) { 97 | setLastEventName('onMoveUpdate'); 98 | print('onMoveUpdate - pos: ${event.localPos} delta: ${event.delta}'); 99 | } 100 | 101 | void onMoveEnd(localPos) { 102 | setLastEventName('onMoveEnd'); 103 | print('onMoveEnd - pos: $localPos'); 104 | } 105 | 106 | void onMoveStart(localPos) { 107 | setLastEventName('onMoveStart'); 108 | print('onMoveStart - pos: $localPos'); 109 | } 110 | 111 | void onLongPress(TapEvent event) { 112 | setLastEventName('onLongPress'); 113 | print('onLongPress - pos: ${event.localPos}'); 114 | } 115 | 116 | void onDoubleTap(event) { 117 | setLastEventName('onDoubleTap'); 118 | print('onDoubleTap - pos: ' + event.localPos.toString()); 119 | } 120 | 121 | void onTap(event) { 122 | setLastEventName('onTap'); 123 | print('onTap - pos: ' + event.localPos.toString()); 124 | } 125 | 126 | void setLastEventName(String eventName) { 127 | setState(() { 128 | lastEventName = eventName; 129 | }); 130 | } 131 | } 132 | 133 | ``` 134 | 135 | ### Customize 136 | 137 | - Change DoubleTap and Long press detect 138 | 139 | ```dart 140 | @override 141 | Widget build(BuildContext context) { 142 | return XGestureDetector( 143 | child: child, 144 | doubleTapTimeConsider: 300, //customize double tap time 145 | longPressTimeConsider: 400, //customize long press time 146 | ); 147 | } 148 | ``` 149 | 150 | - Ignore Tap in case Double Tap dectected 151 | 152 | ```dart 153 | @override 154 | Widget build(BuildContext context) { 155 | return XGestureDetector( 156 | child: child, 157 | bypassTapEventOnDoubleTap: true, // default is false 158 | ); 159 | } 160 | ``` 161 | 162 | - Allow move event after long press event fired without release pointer 163 | 164 | ```dart 165 | @override 166 | Widget build(BuildContext context) { 167 | return XGestureDetector( 168 | child: child, 169 | bypassMoveEventAfterLongPress: false, // default is true 170 | ); 171 | } 172 | ``` 173 | 174 | Checkout the Canvas playground example at https://github.com/taodo2291/xgesture_flutter/tree/master/example/lib/canvas_playground.dart 175 | 176 | 177 | ## Author 178 | Viet Nguyen - taodo2291@gmail.com -------------------------------------------------------------------------------- /xgesture_flutter/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: gesture_x_detector 2 | description: a lightweight gesture detector that supports multiple types(Tap, DoubleTap, Scale, Long-Press, Move) and all callbacks can be used simultaneously 3 | version: 1.0.0 4 | # author: Viet Nguyen 5 | homepage: https://github.com/taodo2291/xgesture_flutter 6 | 7 | environment: 8 | sdk: ">=2.12.0 <3.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | vector_math: ^2.1.0 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | -------------------------------------------------------------------------------- /xgesture_flutter/test/gesture_x_detector_test.dart: -------------------------------------------------------------------------------- 1 | // Import the test package and Counter class 2 | import 'package:flutter_test/flutter_test.dart'; 3 | 4 | void main() { 5 | test('just for fun', () { 6 | expect(1, 1); 7 | }); 8 | } 9 | --------------------------------------------------------------------------------