├── .gitignore ├── .metadata ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── README └── screenshots │ ├── downgrade.png │ ├── installed.png │ ├── installer.png │ ├── installing.png │ ├── main_screen.png │ └── settings_screen.png ├── analysis_options.yaml ├── assets ├── icons │ ├── missing_icon_background.si │ ├── missing_icon_background.xml │ ├── missing_icon_foreground.si │ ├── missing_icon_foreground.xml │ ├── missing_icon_legacy.si │ └── missing_icon_legacy.svg └── images │ └── logo.png ├── embedded-tools ├── AdbWinApi.dll ├── AdbWinUsbApi.dll ├── aapt.exe ├── aapt2.exe ├── adb.exe └── axmldec.exe ├── installer ├── installer.iss └── redist │ └── VC_redist.x64.exe ├── l10n.yaml ├── lib ├── android │ ├── android_utils.dart │ ├── permissions.dart │ ├── reader_apk.dart │ └── reader_xapk.dart ├── apk_installer.dart ├── global_state.dart ├── io │ ├── aapt_input_parse.dart │ └── isolate_runner.dart ├── main.dart ├── proto │ ├── manifest_xapk.pb.dart │ ├── manifest_xapk.pbenum.dart │ ├── manifest_xapk.pbjson.dart │ ├── manifest_xapk.pbserver.dart │ ├── options.pb.dart │ ├── options.pbenum.dart │ ├── options.pbjson.dart │ └── options.pbserver.dart ├── screens │ ├── settings.dart │ └── wsa.dart ├── theme.dart ├── utils │ ├── future_utils.dart │ ├── int_utils.dart │ ├── locale_utils.dart │ ├── misc_utils.dart │ ├── regexp_utils.dart │ ├── string_utils.dart │ └── wsa_utils.dart ├── widget │ ├── adaptive_icon.dart │ ├── flexible_info_bar.dart │ ├── fluent_card.dart │ ├── fluent_combo_box.dart │ ├── fluent_expander.dart │ ├── fluent_info_bar.dart │ ├── fluent_text_box.dart │ ├── move_window_nomax.dart │ ├── smooth_list_view.dart │ └── themed_pane_item.dart └── windows │ ├── nt_io.dart │ ├── win_info.dart │ ├── win_io.dart │ ├── win_path.dart │ ├── win_pkg.dart │ ├── win_reg.dart │ ├── win_wmi.dart │ └── wsa_status.dart ├── locale ├── ar.arb ├── ca.arb ├── de.arb ├── en.arb ├── es.arb ├── fa.arb ├── fr.arb ├── he.arb ├── id.arb ├── it.arb ├── ja.arb ├── ko.arb ├── ku.arb ├── pl.arb ├── pt.arb ├── ru.arb ├── vi.arb ├── zh-Hant.arb └── zh.arb ├── proto ├── manifest_xapk.proto ├── options.proto └── protoc-generate.bat ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart ├── windows ├── .gitignore ├── CMakeLists.txt ├── flutter │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake └── runner │ ├── CMakeLists.txt │ ├── Runner.rc │ ├── flutter_window.cpp │ ├── flutter_window.h │ ├── main.cpp │ ├── resource.h │ ├── resources │ └── app_icon.ico │ ├── run_loop.cpp │ ├── run_loop.h │ ├── runner.exe.manifest │ ├── utils.cpp │ ├── utils.h │ ├── win32_window.cpp │ └── win32_window.h └── winuwp ├── .gitignore ├── CMakeLists.txt ├── flutter ├── CMakeLists.txt ├── generated_plugin_registrant.cc ├── generated_plugin_registrant.h └── generated_plugins.cmake ├── project_version └── runner_uwp ├── Assets ├── LargeTile.scale-100.png ├── LargeTile.scale-125.png ├── LargeTile.scale-150.png ├── LargeTile.scale-200.png ├── LargeTile.scale-400.png ├── LockScreenLogo.scale-200.png ├── SmallTile.scale-100.png ├── SmallTile.scale-125.png ├── SmallTile.scale-150.png ├── SmallTile.scale-200.png ├── SmallTile.scale-400.png ├── SplashScreen.scale-100.png ├── SplashScreen.scale-125.png ├── SplashScreen.scale-150.png ├── SplashScreen.scale-200.png ├── SplashScreen.scale-400.png ├── Square150x150Logo.scale-100.png ├── Square150x150Logo.scale-125.png ├── Square150x150Logo.scale-150.png ├── Square150x150Logo.scale-200.png ├── Square150x150Logo.scale-400.png ├── Square44x44Logo.altform-unplated_targetsize-16.png ├── Square44x44Logo.altform-unplated_targetsize-256.png ├── Square44x44Logo.altform-unplated_targetsize-32.png ├── Square44x44Logo.altform-unplated_targetsize-48.png ├── Square44x44Logo.scale-100.png ├── Square44x44Logo.scale-125.png ├── Square44x44Logo.scale-150.png ├── Square44x44Logo.scale-200.png ├── Square44x44Logo.scale-400.png ├── Square44x44Logo.targetsize-16.png ├── Square44x44Logo.targetsize-24.png ├── Square44x44Logo.targetsize-24_altform-unplated.png ├── Square44x44Logo.targetsize-256.png ├── Square44x44Logo.targetsize-32.png ├── Square44x44Logo.targetsize-48.png ├── StoreLogo.png ├── StoreLogo.scale-100.png ├── StoreLogo.scale-125.png ├── StoreLogo.scale-150.png ├── StoreLogo.scale-200.png ├── StoreLogo.scale-400.png ├── Wide310x150Logo.scale-200.png ├── WideTile.scale-100.png ├── WideTile.scale-125.png ├── WideTile.scale-150.png ├── WideTile.scale-200.png └── WideTile.scale-400.png ├── CMakeLists.txt ├── CMakeSettings.json ├── Windows_TemporaryKey.pfx ├── appxmanifest.in ├── flutter_frameworkview.cpp ├── main.cpp └── resources.pri /.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 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | /android/ 44 | ios/ 45 | linux/ 46 | macos/ -------------------------------------------------------------------------------- /.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: 78910062997c3a836feee883712c241a5fd22983 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Disable null-safety", 5 | "type": "dart", 6 | "request": "launch", 7 | "program": "lib/main.dart", 8 | // Any custom environment variables to set when running the app with this 9 | // launch config. 10 | "env": { 11 | "RELEASE_MODE": false 12 | }, 13 | // Arguments to be passed to the Dart or Flutter app. 14 | "args": [ 15 | "--no-sound-null-safety" 16 | ], 17 | // "debugConsole" or "terminal". If set to "terminal", will run in the built-in 18 | // terminal and will support reading from `stdin`. However some other debug 19 | // features may be limited. 20 | "console": "debugConsole", 21 | 22 | // Set to run a Flutter app on a specific device, ignoring the device selected 23 | // in the status bar. 24 | "deviceId": "windows", 25 | 26 | // "debug", "profile" or "release". 27 | "flutterMode": "profile", 28 | 29 | // Allows running Flutter tests on a real device instead of the default headless 30 | // flutter-tester device. 31 | "runTestsOnDevice": false, 32 | 33 | // If codeLens is defined, this launch configuration can be launched from custom 34 | // CodeLens links in the editor (see the page linked above for more info). 35 | "codeLens": { 36 | 37 | // This array sets where custom CodeLens links will be rendered: 38 | // - run-test: Above test functions as a Run link 39 | // - debug-test: Above test functions as a Debug link 40 | // - run-test-file: Above main functions in test files as a Run link 41 | // - debug-test-file: Above main functions in test files as a Debug link 42 | // - run-file: Above main functions in bin/tool/lib files as a Run link 43 | // - debug-file: Above main functions in bin/tool/lib files as a Debug link 44 | "for": [ "run-test", "run-test-file", "debug-test", "debug-test-file" ], 45 | 46 | // If specificed, the custom CodeLens will only appear for files that begin 47 | // with this path. 48 | "path": "test/integration_tests", 49 | 50 | // Text for the custom CodeLens. If not specified, will use the name field 51 | // from the parent launch configuration. The string "${debugType}" here will 52 | // be replaced with "run" or "debug" depending on the rendered position 53 | // (see the for field above). 54 | "title": "${debugType} (release)" 55 | }, 56 | }, 57 | { 58 | "name": "Release build", 59 | "type": "dart", 60 | "request": "launch", 61 | "program": "lib/main.dart", 62 | // Any custom environment variables to set when running the app with this 63 | // launch config. 64 | "env": { 65 | "RELEASE_MODE": true 66 | }, 67 | // Arguments to be passed to the Dart or Flutter app. 68 | "args": [ 69 | //"--no-sound-null-safety" 70 | ], 71 | // "debugConsole" or "terminal". If set to "terminal", will run in the built-in 72 | // terminal and will support reading from `stdin`. However some other debug 73 | // features may be limited. 74 | "console": "debugConsole", 75 | 76 | // Set to run a Flutter app on a specific device, ignoring the device selected 77 | // in the status bar. 78 | "deviceId": "windows", 79 | 80 | // "debug", "profile" or "release". 81 | "flutterMode": "release", 82 | 83 | // Allows running Flutter tests on a real device instead of the default headless 84 | // flutter-tester device. 85 | "runTestsOnDevice": false, 86 | 87 | // If codeLens is defined, this launch configuration can be launched from custom 88 | // CodeLens links in the editor (see the page linked above for more info). 89 | "codeLens": { 90 | 91 | // This array sets where custom CodeLens links will be rendered: 92 | // - run-test: Above test functions as a Run link 93 | // - debug-test: Above test functions as a Debug link 94 | // - run-test-file: Above main functions in test files as a Run link 95 | // - debug-test-file: Above main functions in test files as a Debug link 96 | // - run-file: Above main functions in bin/tool/lib files as a Run link 97 | // - debug-file: Above main functions in bin/tool/lib files as a Debug link 98 | "for": [ "run-test", "run-test-file", "debug-test", "debug-test-file" ], 99 | 100 | // If specificed, the custom CodeLens will only appear for files that begin 101 | // with this path. 102 | "path": "test/integration_tests", 103 | 104 | // Text for the custom CodeLens. If not specified, will use the name field 105 | // from the parent launch configuration. The string "${debugType}" here will 106 | // be replaced with "run" or "debug" depending on the rendered position 107 | // (see the for field above). 108 | "title": "${debugType} (release)" 109 | }, 110 | } 111 | ] 112 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.arb": "json", 4 | "xstring": "cpp", 5 | "string": "cpp", 6 | "algorithm": "cpp", 7 | "any": "cpp", 8 | "array": "cpp", 9 | "atomic": "cpp", 10 | "cctype": "cpp", 11 | "chrono": "cpp", 12 | "clocale": "cpp", 13 | "cmath": "cpp", 14 | "compare": "cpp", 15 | "concepts": "cpp", 16 | "condition_variable": "cpp", 17 | "cstddef": "cpp", 18 | "cstdint": "cpp", 19 | "cstdio": "cpp", 20 | "cstdlib": "cpp", 21 | "cstring": "cpp", 22 | "cwchar": "cpp", 23 | "exception": "cpp", 24 | "functional": "cpp", 25 | "initializer_list": "cpp", 26 | "ios": "cpp", 27 | "iosfwd": "cpp", 28 | "iostream": "cpp", 29 | "istream": "cpp", 30 | "iterator": "cpp", 31 | "limits": "cpp", 32 | "list": "cpp", 33 | "map": "cpp", 34 | "memory": "cpp", 35 | "mutex": "cpp", 36 | "new": "cpp", 37 | "optional": "cpp", 38 | "ostream": "cpp", 39 | "ratio": "cpp", 40 | "set": "cpp", 41 | "shared_mutex": "cpp", 42 | "sstream": "cpp", 43 | "stdexcept": "cpp", 44 | "streambuf": "cpp", 45 | "system_error": "cpp", 46 | "thread": "cpp", 47 | "tuple": "cpp", 48 | "type_traits": "cpp", 49 | "typeinfo": "cpp", 50 | "unordered_map": "cpp", 51 | "utility": "cpp", 52 | "variant": "cpp", 53 | "vector": "cpp", 54 | "xfacet": "cpp", 55 | "xhash": "cpp", 56 | "xiosbase": "cpp", 57 | "xlocale": "cpp", 58 | "xlocinfo": "cpp", 59 | "xlocnum": "cpp", 60 | "xmemory": "cpp", 61 | "xstddef": "cpp", 62 | "xtr1common": "cpp", 63 | "xtree": "cpp", 64 | "xutility": "cpp" 65 | }, 66 | "cmake.configureOnOpen": false 67 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wsa_pacman 2 | 3 | ![Installer](README/screenshots/installer.png?raw=true "Installer") 4 | 5 | A GUI package manager and package installer for Windows Subsystem for Android (WSA). 6 | 7 | Currently provides a double-click GUI installer for .apk and .xapk files that shows app information (package, icon, version and permissions), allows normal installations as well as upgrades and downgrades. 8 | 9 | The app additionally provides a button to open Android settings and one to open the "Manage Applications" Android settings page, from which you can uninstall or disable applications and grant or revoke permissions 10 | 11 | ## Settings 12 | 13 | - Autostart WSA 14 | - on/off 15 | - Android port 16 | - Default: 58526 17 | - Language 18 | - [All options](./locale/) 19 | - Theme mode 20 | - System 21 | - Dark 22 | - Light 23 | - Window transparency (mica) 24 | - Full 25 | - Partial 26 | - Disabled 27 | - Adaptive icon shape 28 | - Squircle 29 | - Circle 30 | - Rounded square 31 | - Disabled 32 | 33 |

34 | 35 | ## FAQ 36 |

37 | 38 | **Q:** WSA PacMan is always showing the Offline status, why is that? 39 | 40 | **A:** First things first make sure WSA is installed (duh); Open the 'Windows Subsystem for Android™ Settings' app, in the Developer tab and make sure the 'Developer mode' switch is enabled; inside manage developer settings, make sure the 'USB debugging' option is enabled. 41 | 42 | Should all of the above fail, [try following this procedure](https://github.com/alesimula/wsa_pacman/issues/99#issuecomment-1288141314); make sure to check the 'always allow' option. 43 | ## 44 | 45 | **Q:** Can I use WSA PacMan on older versions of Windows (eg. Windows 10)? 46 | 47 | **A:** WSA PacMan depends on Windows Subsystem for Linux, which is only ***officially*** supported on Windows 11. 48 | 49 | However, you may be able to install WSA on Windows 10 [using this project](https://github.com/JimDude7404/WSA-Windows-10) by JimDude7404 and following the step-by-step guide on the GitHub page. 50 | ## 51 | 52 | **Q:** Can i install the Play Store? 53 | 54 | **A:** The play store is not _officially_ supported on WSA, and at the moment it is only possible to install it using an unofficial WSA build. I recommend installing the [Aurora Store](https://auroraoss.com/) instead, which is an unofficial Play Store client; but if you really want the Play Store and other Google apps, [check out this project](https://github.com/LSPosed/MagiskOnWSALocal). 55 | 56 |
57 | 58 |

59 | 60 | ## More screenshots 61 |

62 | 63 | ![Installing](README/screenshots/installing.png?raw=true "Installing") 64 | ![Installed](README/screenshots/installed.png?raw=true "Installed") 65 | ![Downgrade](README/screenshots/downgrade.png?raw=true "Downgrade") 66 | ![Main screen](README/screenshots/main_screen.png?raw=true "Main screen") 67 | ![Settings](README/screenshots/settings_screen.png?raw=true "Settings") 68 |
69 | -------------------------------------------------------------------------------- /README/screenshots/downgrade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/README/screenshots/downgrade.png -------------------------------------------------------------------------------- /README/screenshots/installed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/README/screenshots/installed.png -------------------------------------------------------------------------------- /README/screenshots/installer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/README/screenshots/installer.png -------------------------------------------------------------------------------- /README/screenshots/installing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/README/screenshots/installing.png -------------------------------------------------------------------------------- /README/screenshots/main_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/README/screenshots/main_screen.png -------------------------------------------------------------------------------- /README/screenshots/settings_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/README/screenshots/settings_screen.png -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml -------------------------------------------------------------------------------- /assets/icons/missing_icon_background.si: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/assets/icons/missing_icon_background.si -------------------------------------------------------------------------------- /assets/icons/missing_icon_foreground.si: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/assets/icons/missing_icon_foreground.si -------------------------------------------------------------------------------- /assets/icons/missing_icon_foreground.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 13 | 16 | 19 | 20 | 21 | 22 | 28 | -------------------------------------------------------------------------------- /assets/icons/missing_icon_legacy.si: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/assets/icons/missing_icon_legacy.si -------------------------------------------------------------------------------- /assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/assets/images/logo.png -------------------------------------------------------------------------------- /embedded-tools/AdbWinApi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/embedded-tools/AdbWinApi.dll -------------------------------------------------------------------------------- /embedded-tools/AdbWinUsbApi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/embedded-tools/AdbWinUsbApi.dll -------------------------------------------------------------------------------- /embedded-tools/aapt.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/embedded-tools/aapt.exe -------------------------------------------------------------------------------- /embedded-tools/aapt2.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/embedded-tools/aapt2.exe -------------------------------------------------------------------------------- /embedded-tools/adb.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/embedded-tools/adb.exe -------------------------------------------------------------------------------- /embedded-tools/axmldec.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/embedded-tools/axmldec.exe -------------------------------------------------------------------------------- /installer/installer.iss: -------------------------------------------------------------------------------- 1 | ; -- installer.iss -- 2 | ; Generates an installer with Inno Setup. 3 | 4 | #define tools_dir_name "embedded-tools" 5 | #define releasedir "..\build\windows\runner\Release\" 6 | #define instbuilddir "..\build\installer" 7 | #define toolsdir "..\"+tools_dir_name 8 | 9 | #define vcredist_version "14.31.31103.00" 10 | 11 | #define executable "WSA-pacman.exe" 12 | #define app_name "WSA Package Manager" 13 | #define dist_appname "WSA-pacman" 14 | #define reg_appname "wsa-pacman" 15 | #define reg_name_installer "Package installer" 16 | 17 | #define reg_assoc_xapk reg_appname + ".xapk" 18 | #define reg_assoc_apk reg_appname + ".apk" 19 | 20 | #define path_classes "SOFTWARE\Classes\" 21 | #define path_assoc_user "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\" 22 | #define path_assoc_default ".DEFAULT\"+path_assoc_user 23 | 24 | [Setup] 25 | AppVersion=1.5.0 26 | PrivilegesRequired=admin 27 | AppName=WSA PacMan 28 | AppPublisher=alesimula 29 | ArchitecturesInstallIn64BitMode=x64 30 | WizardStyle=modern 31 | DefaultDirName={autopf}\WSA PacMan 32 | DefaultGroupName=WSA PacMan 33 | UninstallDisplayIcon={app}\{#executable} 34 | Compression=lzma2 35 | SolidCompression=yes 36 | ChangesAssociations=yes 37 | ChangesEnvironment=yes 38 | OutputBaseFilename={#dist_appname}-v{#SetupSetting("AppVersion")}-installer 39 | OutputDir={#instbuilddir} 40 | 41 | [Tasks] 42 | Name: fileassoc_apk; Description: "{cm:AssocFileExtension,{#app_name},.apk}"; 43 | Name: fileassoc_xapk; Description: "{cm:AssocFileExtension,{#app_name},.xapk}"; 44 | 45 | [Registry] 46 | Root: HKA; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; ValueName: "WSA_PACMAN_HOME"; ValueData: "{app}"; Flags: createvalueifdoesntexist preservestringtype uninsdeletevalue 47 | ; File association: apk 48 | Root: HKA; Subkey: "{#path_classes}\.apk"; ValueData: "{#reg_assoc_apk}"; Flags: uninsdeletevalue; ValueType: string; ValueName: "" 49 | Root: HKA; Subkey: "{#path_classes}\.apk\OpenWithProgids"; ValueType: string; ValueName: "{#reg_assoc_apk}"; ValueData: ""; Flags: uninsdeletevalue 50 | Root: HKA; Subkey: "{#path_classes}\{#reg_assoc_apk}"; ValueData: "{#reg_name_installer}"; Flags: uninsdeletekey; ValueType: string; ValueName: "" 51 | Root: HKA; Subkey: "{#path_classes}\{#reg_assoc_apk}\DefaultIcon"; ValueData: "%WSA_PACMAN_HOME%\{#executable},0"; ValueType: expandsz; ValueName: "" 52 | Root: HKA; Subkey: "{#path_classes}\{#reg_assoc_apk}\shell\open\command"; ValueData: """%WSA_PACMAN_HOME%\{#executable}"" ""%1"""; ValueType: expandsz; ValueName: "" 53 | Root: HKU; Subkey: "{#path_assoc_default}\.apk\UserChoice"; ValueType: none; Flags: deletekey; Tasks: fileassoc_apk 54 | Root: HKCU; Subkey: "{#path_assoc_user}\.apk\UserChoice"; ValueType: none; Flags: deletekey; Tasks: fileassoc_apk 55 | ; File association: xapk 56 | Root: HKA; Subkey: "{#path_classes}\.xapk"; ValueData: "{#reg_assoc_xapk}"; Flags: uninsdeletevalue; ValueType: string; ValueName: "" 57 | Root: HKA; Subkey: "{#path_classes}\.xapk\OpenWithProgids"; ValueType: string; ValueName: "{#reg_assoc_xapk}"; ValueData: ""; Flags: uninsdeletevalue 58 | Root: HKA; Subkey: "{#path_classes}\{#reg_assoc_xapk}"; ValueData: "{#reg_name_installer}"; Flags: uninsdeletekey; ValueType: string; ValueName: "" 59 | Root: HKA; Subkey: "{#path_classes}\{#reg_assoc_xapk}\DefaultIcon"; ValueData: "%WSA_PACMAN_HOME%\{#executable},0"; ValueType: expandsz; ValueName: "" 60 | Root: HKA; Subkey: "{#path_classes}\{#reg_assoc_xapk}\shell\open\command"; ValueData: """%WSA_PACMAN_HOME%\{#executable}"" ""%1"""; ValueType: expandsz; ValueName: "" 61 | Root: HKU; Subkey: "{#path_assoc_default}\.xapk\UserChoice"; ValueType: none; Flags: deletekey; Tasks: fileassoc_xapk 62 | Root: HKCU; Subkey: "{#path_assoc_user}\.xapk\UserChoice"; ValueType: none; Flags: deletekey; Tasks: fileassoc_xapk 63 | 64 | [Files] 65 | Source: "{#releasedir}\*"; Excludes: "\*.lib,\*.exp,\{#tools_dir_name}"; DestDir: "{app}"; Flags: recursesubdirs 66 | Source: "{#toolsdir}\*"; DestDir: "{app}\{#tools_dir_name}"; Flags: recursesubdirs 67 | Source: ".\redist\VC_redist.x64.exe"; DestDir: {tmp}; Flags: dontcopy 68 | 69 | [Run] 70 | Filename: "{tmp}\VC_redist.x64.exe"; StatusMsg: "Installing Visual C++ Redistributable..."; \ 71 | Parameters: "/quiet /norestart /install"; Check: ShouldInstallVCRedist; Flags: waituntilterminated 72 | 73 | [Icons] 74 | Name: "{group}\WSA PacMan"; Filename: "{app}\{#executable}" 75 | 76 | [Code] 77 | function ShouldInstallVCRedist: Boolean; 78 | var 79 | Version: String; 80 | begin 81 | if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Version', Version) then 82 | begin 83 | Log('VC Redist Version check : found ' + Version); 84 | //Check if the installed version is lower than the version included in the installer 85 | Result := (CompareStr(Version, 'v{#vcredist_version}')<0); 86 | end 87 | else 88 | begin 89 | // Not even an old version installed 90 | Result := True; 91 | end; 92 | if (Result) then 93 | begin 94 | ExtractTemporaryFile('VC_redist.x64.exe'); 95 | end; 96 | end; 97 | -------------------------------------------------------------------------------- /installer/redist/VC_redist.x64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/installer/redist/VC_redist.x64.exe -------------------------------------------------------------------------------- /l10n.yaml: -------------------------------------------------------------------------------- 1 | arb-dir: locale 2 | template-arb-file: en.arb 3 | output-class: AppLocalizations 4 | output-localization-file: app_localizations.dart -------------------------------------------------------------------------------- /lib/android/android_utils.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: constant_identifier_names 2 | 3 | import 'package:wsa_pacman/android/reader_apk.dart'; 4 | import 'package:wsa_pacman/android/reader_xapk.dart'; 5 | import 'package:wsa_pacman/io/isolate_runner.dart'; 6 | import 'package:wsa_pacman/utils/locale_utils.dart'; 7 | 8 | class Resource { 9 | ResType type; 10 | Iterable values; 11 | Resource(this.values, [this.type = ResType.FILE]); 12 | } 13 | 14 | /// Flags passed to the apk reader isolates 15 | enum APK_READER_FLAGS { 16 | UI_LOADED, LEGACY_ICON 17 | } 18 | 19 | enum InstallState { 20 | PROMPT, INSTALLING, SUCCESS, ERROR, TIMEOUT 21 | } 22 | enum InstallType { 23 | UNKNOWN, INSTALL, REINSTALL, UPDATE, DOWNGRADE 24 | } 25 | enum ResType { 26 | COLOR, POINTER, FILE 27 | } 28 | enum AppPackage { 29 | NONE, APK, XAPK 30 | } 31 | 32 | extension AppPackageType on AppPackage { 33 | static AppPackage fromArguments(List args) => args.isEmpty ? AppPackage.NONE : fromFilename(args.first); 34 | static AppPackage fromFilename(String? name) => name == null || name.isEmpty ? AppPackage.NONE : 35 | name.endsWith(".xapk") ? AppPackage.XAPK : AppPackage.APK; 36 | IsolateRef? Function(String) get read { switch (this) { 37 | case AppPackage.APK: return ApkReader().start; 38 | case AppPackage.XAPK: return XapkReader().start; 39 | case AppPackage.NONE: return (_)=>null; 40 | }} 41 | bool get directInstall => this == AppPackage.APK; 42 | } 43 | 44 | extension InstallTypeExt on InstallType { 45 | String buttonText(AppLocalizations locale) {switch (this) { 46 | case InstallType.UNKNOWN: return locale.installer_btn_install; 47 | case InstallType.INSTALL: return locale.installer_btn_install; 48 | case InstallType.REINSTALL: return locale.installer_btn_reinstall; 49 | case InstallType.UPDATE: return locale.installer_btn_update; 50 | case InstallType.DOWNGRADE: return locale.installer_btn_downgrade; 51 | }} 52 | } 53 | ResType getResType(String typeId) {switch (typeId) { 54 | case "1d": return ResType.COLOR; 55 | case "1c": return ResType.COLOR; 56 | case "1": return ResType.POINTER; 57 | default: return ResType.FILE; 58 | }} 59 | Map fillType = { 60 | "0": "winding", 61 | "1": "evenOdd", 62 | "2": "inverseWinding", 63 | "3": "inverseEvenOdd", 64 | }; 65 | Map gradientType = { 66 | "0": "linear", 67 | "1": "radial", 68 | "2": "sweep" 69 | }; -------------------------------------------------------------------------------- /lib/io/aapt_input_parse.dart: -------------------------------------------------------------------------------- 1 | 2 | // ignore_for_file: curly_braces_in_flow_control_structures 3 | 4 | class Node { 5 | int _hIndex; 6 | Node? parent; 7 | final List values; 8 | final Map children = {}; 9 | 10 | bool get hasValues => values.isNotEmpty; 11 | bool get hasChildren => children.isNotEmpty; 12 | String? get value => values.isNotEmpty ? values[0] : null; 13 | 14 | Node(this._hIndex, this.values, {this.parent}); 15 | Node.single(String value) : this(0, [value]); 16 | Node.empty() : this(0, []); 17 | } 18 | 19 | //Missing grouping and kind of janky 20 | //Using regular expressions for now 21 | Map read(String output) { 22 | bool inThisNode = true; 23 | int? substrIndex = 0; 24 | int? lastNodePos = 0; 25 | Node? lastNode; 26 | Node? newNode; 27 | Map map = {}; 28 | for (var e in output.split('\n')) { 29 | substrIndex = e.indexOf(':'); 30 | if (substrIndex == -1) {newNode = null; continue;} 31 | inThisNode = true; 32 | int nodePos = e.indexOf(RegExp(r'[^\s]')); 33 | int _lastPos = (lastNodePos ?? nodePos); 34 | 35 | String key = e.substring(0,substrIndex).trim(); 36 | String value = e.substring(substrIndex+1).trim(); 37 | 38 | var parent = lastNode?.parent; 39 | if (_lastPos != nodePos || parent != null) { 40 | inThisNode = false; 41 | if (_lastPos < nodePos) { 42 | newNode = Node(nodePos, [value], parent: lastNode); 43 | lastNode!.children[key] = newNode; 44 | lastNode = newNode; 45 | } 46 | else { 47 | while (lastNode!._hIndex != nodePos) lastNode = lastNode.parent; 48 | var parent = lastNode.parent; 49 | if (parent == null) inThisNode = true; 50 | else parent.children[key] = (lastNode = Node(nodePos, [value], parent: parent)); 51 | } 52 | } 53 | lastNodePos = nodePos; 54 | //log("NODE: ${nodePos}"); 55 | if (inThisNode) lastNode = (newNode = Node(nodePos, [value])); 56 | if(key.isNotEmpty && inThisNode) map[key] = newNode!; 57 | } 58 | return map; 59 | } 60 | -------------------------------------------------------------------------------- /lib/io/isolate_runner.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: curly_braces_in_flow_control_structures 2 | 3 | import 'dart:async'; 4 | import 'dart:isolate'; 5 | 6 | import 'package:flutter/foundation.dart'; 7 | import 'package:synchronized/synchronized.dart'; 8 | import 'package:meta/meta.dart'; 9 | 10 | class _IsolateMessage { 11 | final E flag; 12 | final bool value; 13 | _IsolateMessage(this.flag, this.value); 14 | } 15 | 16 | class _IsolateData { 17 | O? data; 18 | final Completer _uiToIsolatePortCompleter; 19 | SendPort? _uiToIsolatePort; 20 | final SendPort _isolateToUiPort; 21 | 22 | _IsolateData._withCompleter(this.data, final Completer portCompleter) : _uiToIsolatePortCompleter = portCompleter, _isolateToUiPort = (ReceivePort()..listen((message) { 23 | if (message is VoidCallback) {message();} 24 | else if (message is SendPort) {portCompleter.complete(message);} 25 | })).sendPort; 26 | 27 | _IsolateData(O data) : this._withCompleter(data, Completer()); 28 | 29 | //Listener has to execute this in the main thread 30 | void _executeInUi(VoidCallback callback) { 31 | _isolateToUiPort.send(callback); 32 | } 33 | void _sendToIsolate(_IsolateMessage a) async { 34 | (_uiToIsolatePort ?? (_uiToIsolatePort = await _uiToIsolatePortCompleter.future)).send(a); 35 | } 36 | } 37 | 38 | class IsolateRef { 39 | final _IsolateData _data; 40 | IsolateRef._(this._data); 41 | 42 | void sendFlag(FLAGS flag, bool value) => _data._sendToIsolate(_IsolateMessage(flag, value)); 43 | } 44 | 45 | /// Simplifies running an isolate 46 | /// Allows running a callback in the UI thread 47 | /// Allows waiting for a signal from the UI thread 48 | /// Most fields are static not to be caught up in the executeInUi method 49 | abstract class IsolateRunner { 50 | static late final _flags = >{}; 51 | static late final _flagsLock = Lock(); 52 | static late final dynamic _data; 53 | static late final _IsolateData _pData; 54 | 55 | /// Data passed to the start method 56 | @nonVirtual O get data => _data; 57 | /// Main runner, must be overridden 58 | @visibleForOverriding FutureOr run(); 59 | /// Executed in the UI thread after starting the isolate 60 | FutureOr postStartCallback(IsolateRef isolate) {} 61 | /// Waits for a flag from the UI thread, may stay locked indefinitely 62 | @nonVirtual Future waitFlag(FLAGS flag) async => await (await _flagsLock.synchronized(()=>_flags.putIfAbsent(flag, ()=>Completer()))).future; 63 | /// Executes a callback in the UI thread 64 | /// Will load all local variables in the current scope if one is referenced, therefore use carefully 65 | @nonVirtual void executeInUi(VoidCallback callback) => _pData._executeInUi(callback); 66 | 67 | void _runInitIsolate(_IsolateData pData) async { 68 | (_pData = pData)._isolateToUiPort.send((ReceivePort()..listen((message) { 69 | if (message is _IsolateMessage) _flagsLock.synchronized(() { 70 | _flags.putIfAbsent(message.flag, ()=>Completer()).complete(message.value); 71 | }); 72 | })).sendPort); 73 | _data = pData.data; 74 | // Should prevent this data from beins sent when launching executeInUi 75 | pData.data = null; 76 | await run(); 77 | } 78 | 79 | @nonVirtual 80 | IsolateRef start(O data) => IsolateRunner._start(this, data); 81 | 82 | /// Starts a process to read apk data 83 | static IsolateRef _start(IsolateRunner runner, O data) { 84 | //APK_FILE = fileName; 85 | //Recheck installation type when connected 86 | final isolateRef = IsolateRef._(_IsolateData(data)); 87 | compute(runner._runInitIsolate, isolateRef._data); 88 | runner.postStartCallback(isolateRef); 89 | return isolateRef; 90 | } 91 | } -------------------------------------------------------------------------------- /lib/proto/manifest_xapk.pbenum.dart: -------------------------------------------------------------------------------- 1 | /// 2 | // Generated code. Do not modify. 3 | // source: manifest_xapk.proto 4 | // 5 | // @dart = 2.12 6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields 7 | 8 | // ignore_for_file: UNDEFINED_SHOWN_NAME 9 | import 'dart:core' as $core; 10 | import 'package:protobuf/protobuf.dart' as $pb; 11 | 12 | class ManifestXapk_InstallDir extends $pb.ProtobufEnum { 13 | static const ManifestXapk_InstallDir EXTERNAL_STORAGE = ManifestXapk_InstallDir._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'EXTERNAL_STORAGE'); 14 | static const ManifestXapk_InstallDir INTERNAL_STORAGE = ManifestXapk_InstallDir._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'INTERNAL_STORAGE'); 15 | 16 | static const $core.List values = [ 17 | EXTERNAL_STORAGE, 18 | INTERNAL_STORAGE, 19 | ]; 20 | 21 | static final $core.Map<$core.int, ManifestXapk_InstallDir> _byValue = $pb.ProtobufEnum.initByValue(values); 22 | static ManifestXapk_InstallDir? valueOf($core.int value) => _byValue[value]; 23 | 24 | const ManifestXapk_InstallDir._($core.int v, $core.String n) : super(v, n); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /lib/proto/manifest_xapk.pbjson.dart: -------------------------------------------------------------------------------- 1 | /// 2 | // Generated code. Do not modify. 3 | // source: manifest_xapk.proto 4 | // 5 | // @dart = 2.12 6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package 7 | 8 | import 'dart:core' as $core; 9 | import 'dart:convert' as $convert; 10 | import 'dart:typed_data' as $typed_data; 11 | @$core.Deprecated('Use manifestXapkDescriptor instead') 12 | const ManifestXapk$json = const { 13 | '1': 'ManifestXapk', 14 | '2': const [ 15 | const {'1': 'xapk_version', '3': 1, '4': 1, '5': 13, '7': '1', '10': 'xapkVersion'}, 16 | const {'1': 'package_name', '3': 2, '4': 1, '5': 9, '10': 'packageName'}, 17 | const {'1': 'name', '3': 3, '4': 1, '5': 9, '10': 'name'}, 18 | const {'1': 'locales_name', '3': 4, '4': 3, '5': 11, '6': '.proto.ManifestXapk.LocalesNameEntry', '10': 'localesName'}, 19 | const {'1': 'version_code', '3': 5, '4': 1, '5': 13, '10': 'versionCode'}, 20 | const {'1': 'version_name', '3': 6, '4': 1, '5': 9, '10': 'versionName'}, 21 | const {'1': 'min_sdk_version', '3': 7, '4': 1, '5': 13, '10': 'minSdkVersion'}, 22 | const {'1': 'target_sdk_version', '3': 8, '4': 1, '5': 13, '10': 'targetSdkVersion'}, 23 | const {'1': 'permissions', '3': 9, '4': 3, '5': 9, '10': 'permissions'}, 24 | const {'1': 'split_configs', '3': 10, '4': 3, '5': 9, '10': 'splitConfigs'}, 25 | const {'1': 'total_size', '3': 11, '4': 1, '5': 13, '10': 'totalSize'}, 26 | const {'1': 'icon', '3': 12, '4': 1, '5': 9, '10': 'icon'}, 27 | const {'1': 'split_apks', '3': 13, '4': 3, '5': 11, '6': '.proto.ManifestXapk.ApkFile', '10': 'splitApks'}, 28 | const {'1': 'expansions', '3': 14, '4': 3, '5': 11, '6': '.proto.ManifestXapk.ApkExpansion', '10': 'expansions'}, 29 | ], 30 | '3': const [ManifestXapk_LocalesNameEntry$json, ManifestXapk_ApkFile$json, ManifestXapk_ApkExpansion$json], 31 | '4': const [ManifestXapk_InstallDir$json], 32 | }; 33 | 34 | @$core.Deprecated('Use manifestXapkDescriptor instead') 35 | const ManifestXapk_LocalesNameEntry$json = const { 36 | '1': 'LocalesNameEntry', 37 | '2': const [ 38 | const {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, 39 | const {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, 40 | ], 41 | '7': const {'7': true}, 42 | }; 43 | 44 | @$core.Deprecated('Use manifestXapkDescriptor instead') 45 | const ManifestXapk_ApkFile$json = const { 46 | '1': 'ApkFile', 47 | '2': const [ 48 | const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'}, 49 | const {'1': 'file', '3': 2, '4': 1, '5': 9, '10': 'file'}, 50 | ], 51 | }; 52 | 53 | @$core.Deprecated('Use manifestXapkDescriptor instead') 54 | const ManifestXapk_ApkExpansion$json = const { 55 | '1': 'ApkExpansion', 56 | '2': const [ 57 | const {'1': 'install_location', '3': 1, '4': 1, '5': 14, '6': '.proto.ManifestXapk.InstallDir', '10': 'installLocation'}, 58 | const {'1': 'file', '3': 2, '4': 1, '5': 9, '10': 'file'}, 59 | const {'1': 'install_path', '3': 3, '4': 1, '5': 9, '10': 'installPath'}, 60 | ], 61 | }; 62 | 63 | @$core.Deprecated('Use manifestXapkDescriptor instead') 64 | const ManifestXapk_InstallDir$json = const { 65 | '1': 'InstallDir', 66 | '2': const [ 67 | const {'1': 'EXTERNAL_STORAGE', '2': 0}, 68 | const {'1': 'INTERNAL_STORAGE', '2': 1}, 69 | ], 70 | }; 71 | 72 | /// Descriptor for `ManifestXapk`. Decode as a `google.protobuf.DescriptorProto`. 73 | final $typed_data.Uint8List manifestXapkDescriptor = $convert.base64Decode('CgxNYW5pZmVzdFhhcGsSJAoMeGFwa192ZXJzaW9uGAEgASgNOgExUgt4YXBrVmVyc2lvbhIhCgxwYWNrYWdlX25hbWUYAiABKAlSC3BhY2thZ2VOYW1lEhIKBG5hbWUYAyABKAlSBG5hbWUSRwoMbG9jYWxlc19uYW1lGAQgAygLMiQucHJvdG8uTWFuaWZlc3RYYXBrLkxvY2FsZXNOYW1lRW50cnlSC2xvY2FsZXNOYW1lEiEKDHZlcnNpb25fY29kZRgFIAEoDVILdmVyc2lvbkNvZGUSIQoMdmVyc2lvbl9uYW1lGAYgASgJUgt2ZXJzaW9uTmFtZRImCg9taW5fc2RrX3ZlcnNpb24YByABKA1SDW1pblNka1ZlcnNpb24SLAoSdGFyZ2V0X3Nka192ZXJzaW9uGAggASgNUhB0YXJnZXRTZGtWZXJzaW9uEiAKC3Blcm1pc3Npb25zGAkgAygJUgtwZXJtaXNzaW9ucxIjCg1zcGxpdF9jb25maWdzGAogAygJUgxzcGxpdENvbmZpZ3MSHQoKdG90YWxfc2l6ZRgLIAEoDVIJdG90YWxTaXplEhIKBGljb24YDCABKAlSBGljb24SOgoKc3BsaXRfYXBrcxgNIAMoCzIbLnByb3RvLk1hbmlmZXN0WGFway5BcGtGaWxlUglzcGxpdEFwa3MSQAoKZXhwYW5zaW9ucxgOIAMoCzIgLnByb3RvLk1hbmlmZXN0WGFway5BcGtFeHBhbnNpb25SCmV4cGFuc2lvbnMaPgoQTG9jYWxlc05hbWVFbnRyeRIQCgNrZXkYASABKAlSA2tleRIUCgV2YWx1ZRgCIAEoCVIFdmFsdWU6AjgBGi0KB0Fwa0ZpbGUSDgoCaWQYASABKAlSAmlkEhIKBGZpbGUYAiABKAlSBGZpbGUakAEKDEFwa0V4cGFuc2lvbhJJChBpbnN0YWxsX2xvY2F0aW9uGAEgASgOMh4ucHJvdG8uTWFuaWZlc3RYYXBrLkluc3RhbGxEaXJSD2luc3RhbGxMb2NhdGlvbhISCgRmaWxlGAIgASgJUgRmaWxlEiEKDGluc3RhbGxfcGF0aBgDIAEoCVILaW5zdGFsbFBhdGgiOAoKSW5zdGFsbERpchIUChBFWFRFUk5BTF9TVE9SQUdFEAASFAoQSU5URVJOQUxfU1RPUkFHRRAB'); 74 | -------------------------------------------------------------------------------- /lib/proto/manifest_xapk.pbserver.dart: -------------------------------------------------------------------------------- 1 | /// 2 | // Generated code. Do not modify. 3 | // source: manifest_xapk.proto 4 | // 5 | // @dart = 2.12 6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package 7 | 8 | export 'manifest_xapk.pb.dart'; 9 | 10 | -------------------------------------------------------------------------------- /lib/proto/options.pbenum.dart: -------------------------------------------------------------------------------- 1 | /// 2 | // Generated code. Do not modify. 3 | // source: options.proto 4 | // 5 | // @dart = 2.12 6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields 7 | 8 | // ignore_for_file: UNDEFINED_SHOWN_NAME 9 | import 'dart:core' as $core; 10 | import 'package:protobuf/protobuf.dart' as $pb; 11 | 12 | class Options_Theme extends $pb.ProtobufEnum { 13 | static const Options_Theme SYSTEM = Options_Theme._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SYSTEM'); 14 | static const Options_Theme LIGHT = Options_Theme._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'LIGHT'); 15 | static const Options_Theme DARK = Options_Theme._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DARK'); 16 | 17 | static const $core.List values = [ 18 | SYSTEM, 19 | LIGHT, 20 | DARK, 21 | ]; 22 | 23 | static final $core.Map<$core.int, Options_Theme> _byValue = $pb.ProtobufEnum.initByValue(values); 24 | static Options_Theme? valueOf($core.int value) => _byValue[value]; 25 | 26 | const Options_Theme._($core.int v, $core.String n) : super(v, n); 27 | } 28 | 29 | class Options_IconShape extends $pb.ProtobufEnum { 30 | static const Options_IconShape SQUIRCLE = Options_IconShape._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SQUIRCLE'); 31 | static const Options_IconShape CIRCLE = Options_IconShape._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CIRCLE'); 32 | static const Options_IconShape ROUNDED_SQUARE = Options_IconShape._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ROUNDED_SQUARE'); 33 | 34 | static const $core.List values = [ 35 | SQUIRCLE, 36 | CIRCLE, 37 | ROUNDED_SQUARE, 38 | ]; 39 | 40 | static final $core.Map<$core.int, Options_IconShape> _byValue = $pb.ProtobufEnum.initByValue(values); 41 | static Options_IconShape? valueOf($core.int value) => _byValue[value]; 42 | 43 | const Options_IconShape._($core.int v, $core.String n) : super(v, n); 44 | } 45 | 46 | class Options_Mica extends $pb.ProtobufEnum { 47 | static const Options_Mica FULL = Options_Mica._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'FULL'); 48 | static const Options_Mica PARTIAL = Options_Mica._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PARTIAL'); 49 | static const Options_Mica DISABLED = Options_Mica._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DISABLED'); 50 | 51 | static const $core.List values = [ 52 | FULL, 53 | PARTIAL, 54 | DISABLED, 55 | ]; 56 | 57 | static final $core.Map<$core.int, Options_Mica> _byValue = $pb.ProtobufEnum.initByValue(values); 58 | static Options_Mica? valueOf($core.int value) => _byValue[value]; 59 | 60 | const Options_Mica._($core.int v, $core.String n) : super(v, n); 61 | } 62 | 63 | -------------------------------------------------------------------------------- /lib/proto/options.pbjson.dart: -------------------------------------------------------------------------------- 1 | /// 2 | // Generated code. Do not modify. 3 | // source: options.proto 4 | // 5 | // @dart = 2.12 6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package 7 | 8 | import 'dart:core' as $core; 9 | import 'dart:convert' as $convert; 10 | import 'dart:typed_data' as $typed_data; 11 | @$core.Deprecated('Use optionsDescriptor instead') 12 | const Options$json = const { 13 | '1': 'Options', 14 | '2': const [ 15 | const {'1': 'ipAddress', '3': 1, '4': 1, '5': 13, '7': '2130706433', '10': 'ipAddress'}, 16 | const {'1': 'port', '3': 2, '4': 1, '5': 13, '7': '58526', '10': 'port'}, 17 | const {'1': 'autostart', '3': 8, '4': 1, '5': 8, '10': 'autostart'}, 18 | const {'1': 'timeout', '3': 10, '4': 1, '5': 13, '7': '30', '10': 'timeout'}, 19 | const {'1': 'locale', '3': 9, '4': 1, '5': 13, '10': 'locale'}, 20 | const {'1': 'theme', '3': 3, '4': 1, '5': 14, '6': '.proto.Options.Theme', '10': 'theme'}, 21 | const {'1': 'legacyIcons', '3': 4, '4': 1, '5': 8, '10': 'legacyIcons'}, 22 | const {'1': 'systemAccent', '3': 5, '4': 1, '5': 8, '10': 'systemAccent'}, 23 | const {'1': 'iconShape', '3': 6, '4': 1, '5': 14, '6': '.proto.Options.IconShape', '10': 'iconShape'}, 24 | const {'1': 'mica', '3': 7, '4': 1, '5': 14, '6': '.proto.Options.Mica', '7': 'FULL', '10': 'mica'}, 25 | ], 26 | '4': const [Options_Theme$json, Options_IconShape$json, Options_Mica$json], 27 | }; 28 | 29 | @$core.Deprecated('Use optionsDescriptor instead') 30 | const Options_Theme$json = const { 31 | '1': 'Theme', 32 | '2': const [ 33 | const {'1': 'SYSTEM', '2': 0}, 34 | const {'1': 'LIGHT', '2': 1}, 35 | const {'1': 'DARK', '2': 2}, 36 | ], 37 | }; 38 | 39 | @$core.Deprecated('Use optionsDescriptor instead') 40 | const Options_IconShape$json = const { 41 | '1': 'IconShape', 42 | '2': const [ 43 | const {'1': 'SQUIRCLE', '2': 0}, 44 | const {'1': 'CIRCLE', '2': 1}, 45 | const {'1': 'ROUNDED_SQUARE', '2': 2}, 46 | ], 47 | }; 48 | 49 | @$core.Deprecated('Use optionsDescriptor instead') 50 | const Options_Mica$json = const { 51 | '1': 'Mica', 52 | '2': const [ 53 | const {'1': 'FULL', '2': 0}, 54 | const {'1': 'PARTIAL', '2': 1}, 55 | const {'1': 'DISABLED', '2': 2}, 56 | ], 57 | }; 58 | 59 | /// Descriptor for `Options`. Decode as a `google.protobuf.DescriptorProto`. 60 | final $typed_data.Uint8List optionsDescriptor = $convert.base64Decode('CgdPcHRpb25zEigKCWlwQWRkcmVzcxgBIAEoDToKMjEzMDcwNjQzM1IJaXBBZGRyZXNzEhkKBHBvcnQYAiABKA06BTU4NTI2UgRwb3J0EhwKCWF1dG9zdGFydBgIIAEoCFIJYXV0b3N0YXJ0EhwKB3RpbWVvdXQYCiABKA06AjMwUgd0aW1lb3V0EhYKBmxvY2FsZRgJIAEoDVIGbG9jYWxlEioKBXRoZW1lGAMgASgOMhQucHJvdG8uT3B0aW9ucy5UaGVtZVIFdGhlbWUSIAoLbGVnYWN5SWNvbnMYBCABKAhSC2xlZ2FjeUljb25zEiIKDHN5c3RlbUFjY2VudBgFIAEoCFIMc3lzdGVtQWNjZW50EjYKCWljb25TaGFwZRgGIAEoDjIYLnByb3RvLk9wdGlvbnMuSWNvblNoYXBlUglpY29uU2hhcGUSLQoEbWljYRgHIAEoDjITLnByb3RvLk9wdGlvbnMuTWljYToERlVMTFIEbWljYSIoCgVUaGVtZRIKCgZTWVNURU0QABIJCgVMSUdIVBABEggKBERBUksQAiI5CglJY29uU2hhcGUSDAoIU1FVSVJDTEUQABIKCgZDSVJDTEUQARISCg5ST1VOREVEX1NRVUFSRRACIisKBE1pY2ESCAoERlVMTBAAEgsKB1BBUlRJQUwQARIMCghESVNBQkxFRBAC'); 61 | -------------------------------------------------------------------------------- /lib/proto/options.pbserver.dart: -------------------------------------------------------------------------------- 1 | /// 2 | // Generated code. Do not modify. 3 | // source: options.proto 4 | // 5 | // @dart = 2.12 6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package 7 | 8 | export 'options.pb.dart'; 9 | 10 | -------------------------------------------------------------------------------- /lib/screens/wsa.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_print 2 | 3 | import 'dart:io'; 4 | 5 | import 'package:fluent_ui/fluent_ui.dart'; 6 | import 'package:mdi/mdi.dart'; 7 | import 'package:wsa_pacman/utils/wsa_utils.dart'; 8 | import 'package:wsa_pacman/widget/fluent_card.dart'; 9 | import 'package:wsa_pacman/widget/fluent_info_bar.dart'; 10 | import 'package:wsa_pacman/widget/smooth_list_view.dart'; 11 | import '../main.dart'; 12 | import '../global_state.dart'; 13 | 14 | class ScreenWSA extends StatefulWidget { 15 | const ScreenWSA({Key? key}) : super(key: key); 16 | 17 | @override 18 | _ScreenWSAState createState() => _ScreenWSAState(); 19 | } 20 | 21 | class EmptyElement extends Element { 22 | EmptyElement(Empty widget) : super(widget); 23 | @override 24 | void performRebuild() {} 25 | @override 26 | bool get debugDoingBuild => false; 27 | @override 28 | Empty get widget => super.widget as Empty; 29 | } 30 | class Empty extends Widget { 31 | const Empty(); 32 | 33 | @override 34 | Element createElement() => EmptyElement(this); 35 | } 36 | Expanded EMPTY = Expanded(child: Column()); 37 | 38 | class _ScreenWSAState extends State { 39 | //_FormsState(this.gsmap); 40 | 41 | //final GSMap gsmap; 42 | final autoSuggestBox = TextEditingController(); 43 | 44 | final _clearController = TextEditingController(); 45 | bool _showPassword = false; 46 | final values = ['Blue', 'Green', 'Yellow', 'Red']; 47 | String? comboBoxValue; 48 | 49 | DateTime date = DateTime.now(); 50 | 51 | @override 52 | Widget build(BuildContext context) { 53 | var connectionStatus = GState.connectionStatus.of(context); 54 | final lang = AppLocalizations.of(context)!; 55 | 56 | const smallSpacer = SizedBox(height: 5.0); 57 | 58 | return ScaffoldPage( 59 | header: PageHeader(title: Text(lang.screen_wsa)), 60 | content: SmoothListView( 61 | padding: EdgeInsets.only( 62 | bottom: kPageDefaultVerticalPadding, 63 | left: PageHeader.horizontalPadding(context), 64 | right: PageHeader.horizontalPadding(context), 65 | ), 66 | children: [ 67 | Padding( 68 | padding: const EdgeInsets.only(bottom: 8.0), 69 | child: FluentInfoBar( 70 | title: Text(connectionStatus.title(lang)), 71 | content: Wrap(crossAxisAlignment: WrapCrossAlignment.center, children: [ 72 | Text(connectionStatus.desc(lang)), 73 | if (connectionStatus.type == ConnectionStatus.ARRESTED) ...[ 74 | const SizedBox(width: 15.0), 75 | Button(child: Text(lang.btn_boot), onPressed: () => WSAUtils.launch()) 76 | ] 77 | else if (connectionStatus.type == ConnectionStatus.UNAUTHORIZED) ...[ 78 | Button(child: Text(lang.btn_auth), onPressed: () => WSAPeriodicConnector.reconnect()), 79 | const SizedBox(width: 15.0), 80 | Button(child: Text(lang.btn_dev_settings), onPressed: () => WSAUtils.launchDeveloperSettings()) 81 | ], 82 | ]), 83 | isLong: true, 84 | severity: connectionStatus.severity, 85 | action: () { 86 | // Do nothing for now 87 | }(), 88 | ) 89 | ), 90 | const SizedBox(height: 20), 91 | Text(lang.wsa_manage, style: FluentTheme.of(context).typography.bodyLarge), 92 | const SizedBox(height: 20), 93 | FluentCard( 94 | leading: const Icon(Mdi.android , size: 23), 95 | content: Text(lang.wsa_manage_app), 96 | isButton: true, 97 | onPressed: connectionStatus.isDisconnected ? 98 | null : () => ADBUtils.shellToAddress(GState.ipAddress.of(context), GState.androidPort.of(context), 99 | r'am start -f 0x10008000 -n com.android.settings/.Settings\$ManageApplicationsActivity'), 100 | ), 101 | smallSpacer, 102 | FluentCard( 103 | leading: const Icon(Mdi.cogs, size: 23), 104 | content: Text(lang.wsa_manage_settings), 105 | isButton: true, 106 | onPressed: connectionStatus.isDisconnected ? 107 | connectionStatus.isPoweredOn ? () => WSAUtils.launchSettings() : null : 108 | () => ADBUtils.shellToAddress(GState.ipAddress.of(context), GState.androidPort.of(context), 109 | r'am start com.android.settings/.Settings'), 110 | ) 111 | 112 | ], 113 | ), 114 | ); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluent_ui/fluent_ui.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | import 'package:system_theme/system_theme.dart'; 4 | import 'package:flutter_acrylic/flutter_acrylic.dart' as flutter_acrylic; 5 | 6 | enum NavigationIndicators { sticky, end } 7 | 8 | class AppTheme extends ChangeNotifier { 9 | static final AccentColor alpineLandingDark = AccentColor('normal', const { 10 | 'darkest': Color(0xff126568), 11 | 'darker': Color(0xff146D70), 12 | 'dark': Color(0xff157477), 13 | 'normal': Color(0xff167C80), 14 | 'light': Color(0xff188387), 15 | 'lighter': Color(0xff198A8E), 16 | 'lightest': Color(0xff1B9296), 17 | }); 18 | static final AccentColor alpineLandingLight = AccentColor('normal', const { 19 | 'darkest': Color(0xff167C80), 20 | 'darker': Color(0xff188387), 21 | 'dark': Color(0xff198A8E), 22 | 'normal': Color(0xff1C9EA0), 23 | 'light': Color(0xff1DA5A5), 24 | 'lighter': Color(0xff20B2B2), 25 | 'lightest': Color(0xff21B7B7), 26 | }); 27 | AccentColor? _color; //Alpine landing FTW 28 | AccentColor getColor(bool darkMode) => _color ?? (darkMode ? alpineLandingDark : alpineLandingLight); 29 | void setColor(AccentColor color) { 30 | _color = (identical(color, alpineLandingDark) || identical(color, alpineLandingLight)) ? null : color; 31 | notifyListeners(); 32 | } 33 | 34 | PaneDisplayMode _displayMode = PaneDisplayMode.top; 35 | PaneDisplayMode get displayMode => _displayMode; 36 | set displayMode(PaneDisplayMode displayMode) { 37 | _displayMode = displayMode; 38 | notifyListeners(); 39 | } 40 | 41 | NavigationIndicators _indicator = NavigationIndicators.sticky; 42 | NavigationIndicators get indicator => _indicator; 43 | set indicator(NavigationIndicators indicator) { 44 | _indicator = indicator; 45 | notifyListeners(); 46 | } 47 | 48 | /*flutter_acrylic.AcrylicEffect _acrylicEffect = 49 | flutter_acrylic.AcrylicEffect.disabled; 50 | flutter_acrylic.AcrylicEffect get acrylicEffect => _acrylicEffect; 51 | set acrylicEffect(flutter_acrylic.AcrylicEffect acrylicEffect) { 52 | _acrylicEffect = acrylicEffect; 53 | notifyListeners(); 54 | }*/ 55 | } 56 | 57 | AccentColor get systemAccentColor { 58 | if (defaultTargetPlatform == TargetPlatform.windows || 59 | defaultTargetPlatform == TargetPlatform.android || 60 | kIsWeb) { 61 | return AccentColor('normal', { 62 | 'darkest': SystemTheme.accentColor.darkest, 63 | 'darker': SystemTheme.accentColor.darker, 64 | 'dark': SystemTheme.accentColor.dark, 65 | 'normal': SystemTheme.accentColor.accent, 66 | 'light': SystemTheme.accentColor.light, 67 | 'lighter': SystemTheme.accentColor.lighter, 68 | 'lightest': SystemTheme.accentColor.lightest, 69 | }); 70 | } 71 | return Colors.blue; 72 | } 73 | -------------------------------------------------------------------------------- /lib/utils/future_utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | extension FutureOrUtils on FutureOr { 4 | Future thenOr(FutureOr Function(T value) onValue) { 5 | if (this is Future) { 6 | return (this as Future).then(onValue); 7 | } else { 8 | return Future.value(onValue(this as T)); 9 | } 10 | } 11 | } 12 | 13 | extension FutureIterableUtils on Iterable> { 14 | FutureOr foldFuturesSkipNulls(T Function(T previousValue, T element) combine) { 15 | return fold(Future.value(null), (f1, f2) => f1.thenOr((e1)=>f2.thenOr((e2) => Future.value(e1 == null ? e2 : e2 == null ? e1 : combine(e1, e2))))); 16 | } 17 | } -------------------------------------------------------------------------------- /lib/utils/int_utils.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: constant_identifier_names 2 | 3 | import 'dart:io'; 4 | 5 | import 'dart:typed_data'; 6 | 7 | extension IntUtils on int { 8 | static const int LOCALHOST = 2130706433; 9 | 10 | String get asIpv4 => InternetAddress.fromRawAddress(Uint8List(4)..buffer.asByteData().setInt32(0, this)).address; 11 | } -------------------------------------------------------------------------------- /lib/utils/misc_utils.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: curly_braces_in_flow_control_structures 2 | 3 | import 'dart:async'; 4 | import 'dart:io'; 5 | import 'package:path/path.dart' as lib_path; 6 | import 'package:archive/archive.dart'; 7 | import '../windows/win_io.dart'; 8 | import 'package:fluent_ui/fluent_ui.dart'; 9 | 10 | class DynamicTimer { 11 | int _durationUs; 12 | int _tick = 0; 13 | final void Function(Timer timer) _callback; 14 | Timer? _timer; 15 | 16 | DynamicTimer(this._callback) : _durationUs = -1; 17 | DynamicTimer.periodic(Duration _duration, this._callback) : _durationUs = _duration.inMicroseconds, _timer = Timer.periodic(_duration, _callback); 18 | 19 | void cancel() => _timer?.cancel(); 20 | int get tick => _tick + (_timer?.tick ?? 0); 21 | bool get isActive => _timer?.isActive ?? false; 22 | 23 | /// Starts or restarts the timer with a new duration 24 | void setDuration(Duration duration) { 25 | if (duration.inMicroseconds == _durationUs) return; 26 | _timer?.cancel(); 27 | _tick += _timer?.tick ?? 0; 28 | _durationUs = duration.inMicroseconds; 29 | _timer = Timer.periodic(duration, _callback); 30 | } 31 | } 32 | 33 | class ColorConst extends Color { 34 | const ColorConst.withOpacity(int value, double opacity) : super( 35 | ( (((opacity * 0xff ~/ 1) & 0xff) << 24) | ((0x00ffffff & value)) ) & 0xFFFFFFFF); 36 | } 37 | 38 | extension EdgeInsetsUtils on EdgeInsets { 39 | EdgeInsetsDirectional directional() => this is EdgeInsetsDirectional ? this as EdgeInsetsDirectional : EdgeInsetsDirectional.fromSTEB(left, top, right, bottom); 40 | } 41 | 42 | extension FileUtils on FileSystemEntity { 43 | String get basename => lib_path.basename(path); 44 | } 45 | 46 | extension MapUtils on Map { 47 | List getAll(Iterable keys) { 48 | List list = []; 49 | for (var key in keys) { 50 | final value = this[key]; 51 | if (value!=null) list.add(value); 52 | } 53 | return list; 54 | } 55 | } 56 | 57 | extension ArchiveUtils on Archive { 58 | List getFiles(Iterable? names) { 59 | List files = []; 60 | if (names == null || names.isEmpty) return files; 61 | var regex = RegExp('^(${names.join("|")})\$'); 62 | for (var file in this.files) { 63 | if (regex.hasMatch(file.name)) files.add(file); 64 | } 65 | return files; 66 | } 67 | 68 | Future extractAll(Directory directory, {bool replaceExisting = false, FileDisposeQueue? disposeLock}) async => extractAllSync(directory, replaceExisting: replaceExisting, disposeLock: disposeLock); 69 | bool extractAllSync(Directory directory, {bool replaceExisting = false, FileDisposeQueue? disposeLock }) { 70 | bool success = true; 71 | Future.wait([for (final file in files) () async {if (file.extractSync(directory, replaceExisting: replaceExisting, disposeLock: disposeLock)) success = false;}()]); 72 | return success; 73 | } 74 | } 75 | 76 | extension ArchiveFileUtils on ArchiveFile { 77 | Future extract(Directory directory, {bool replaceExisting = false, FileDisposeQueue? disposeLock}) async => extractSync(directory, replaceExisting: replaceExisting, disposeLock: disposeLock); 78 | bool extractSync(Directory directory, {bool replaceExisting = false, FileDisposeQueue? disposeLock}) { 79 | final file = File("${directory.absolute.path}\\$name"); 80 | bool confirmExist = false; 81 | if (!replaceExisting && (confirmExist = file.existsSync())) return false; 82 | if (!confirmExist) file..createSync(recursive: true)..writeAsBytesSync(content); 83 | disposeLock?.add(file); 84 | return true; 85 | } 86 | } -------------------------------------------------------------------------------- /lib/utils/regexp_utils.dart: -------------------------------------------------------------------------------- 1 | const String REGEX_XML_NOCLOSE = '[^\'">]*("[^"]*"[^">]*|\'[^\']*\'[^\'">]*)*'; 2 | const String REGEX_XML_QUOTED = "[\"][^\"]*[\"]|['][^']*[']"; 3 | String REGEX_QUOTED_PATTERN(String Function(String quoteChar) regex) => '("${regex('"')}"|\'${regex("'")}\')'; -------------------------------------------------------------------------------- /lib/utils/string_utils.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: curly_braces_in_flow_control_structures 2 | 3 | import 'dart:collection'; 4 | import 'dart:ui'; 5 | import 'dart:io'; 6 | 7 | extension StringUtils on String { 8 | Locale? get asLocale => findAnd(r"^([a-z]*)([_-]([A-Za-z][a-z]{2,3}))?([_-]([A-Z]*))?", (m) => m.group(1)?.isNotEmpty ?? false ? 9 | Locale.fromSubtags(languageCode: m.group(1)!, countryCode: m.group(5)?.isNotEmpty ?? false ? m.group(5)! : null, 10 | scriptCode: m.group(3)?.isNotEmpty ?? false ? m.group(3)! : null) : null); 11 | int? get ipv4AsInt => InternetAddress.tryParse(this)?.rawAddress.buffer.asByteData().getInt32(0); 12 | 13 | String get capitalized => '${this[0].toUpperCase()}${substring(1)}'; 14 | String get normalized => '${this[0].toUpperCase()}${replaceAll('_', ' ').substring(1).toLowerCase()}'; 15 | String get unquoted => RegExp('^["\']?([^\'"]*([\'"][^\$])*)["\']?\$', multiLine: true).firstMatch(this)?.group(1) ?? this; 16 | 17 | /// Is 7-bit ASCII only 18 | bool get isASCII => RegExp(r'^[\x00-\x7F]+$', multiLine: true, dotAll: true).hasMatch(this); 19 | bool isNumeric() => contains(RegExp(r'^[0-9]*$')); 20 | bool isSignedNumeric() => contains(RegExp(r'^[+-]?[0-9]*$')); 21 | 22 | String? find(String regexp, [int group = 0]) { 23 | var matches = RegExp(regexp).firstMatch(this); 24 | return matches?.group(group); 25 | } 26 | 27 | /// Maps folding repeated entries per key 28 | Map foldToMap(String regexp, K Function(RegExpMatch match) key, V Function(RegExpMatch match, V? prev) value) { 29 | Map map = {}; 30 | for (var m in RegExp(regexp).allMatches(this)) map.update(key(m), (v) => value(m, v), ifAbsent: () => value(m, null)); 31 | return map; 32 | } 33 | 34 | /// Maps the string, assumes a single match per key 35 | Map toMap(String regexp, K Function(RegExpMatch match) key, V Function(RegExpMatch match) value) { 36 | return {for (var m in RegExp(regexp).allMatches(this)) key(m) : value(m)}; 37 | } 38 | 39 | /// Maps the string, assumes a single match per key 40 | Set toSet(String regexp, E? Function(RegExpMatch match) value, [int Function(E key1, E key2)? compare]) { 41 | final Set set = compare != null ? SplayTreeSet(compare) : {}; 42 | for (var m in RegExp(regexp).allMatches(this)) { 43 | var nv = value(m); 44 | if (nv != null) set.add(nv); 45 | else if (null is E) (set as Set).add(nv); 46 | } 47 | return set; 48 | } 49 | 50 | Iterable findAll(String regexp, [int group = 0]) { 51 | return RegExp(regexp).allMatches(this).map((m) => m.group(group)!); 52 | } 53 | 54 | Iterable findAllAnd(String regexp, R Function(RegExpMatch match) provider) { 55 | return RegExp(regexp).allMatches(this).map((m) => provider(m)); 56 | } 57 | 58 | R? findAnd(String regexp, R Function(RegExpMatch match) provider) { 59 | final match = RegExp(regexp).firstMatch(this); 60 | return match != null ? provider(match) : null; 61 | } 62 | } -------------------------------------------------------------------------------- /lib/widget/adaptive_icon.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' hide log; 2 | import 'package:fluent_ui/fluent_ui.dart'; 3 | 4 | //Display an Android adaptive icon 5 | //TODO not immutable 6 | class AdaptiveIcon extends StatelessWidget { 7 | final double _scale; 8 | final double radius; 9 | Color? backColor; 10 | Widget? background; 11 | Widget? foreground; 12 | 13 | AdaptiveIcon({Key? key, this.radius = 0.6, this.background, this.foreground, this.backColor, bool noScale = false}) : _scale = noScale ? 1 : 1.5 ,super(key: key); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return SizedBox( 18 | child: FractionallySizedBox( 19 | heightFactor: 1, 20 | widthFactor: 1, 21 | child: LayoutBuilder( 22 | builder: (context, BoxConstraints constraints) { 23 | final borderRadius = min(constraints.maxWidth, constraints.maxHeight) * radius/2; 24 | return Center( 25 | child: AspectRatio ( 26 | aspectRatio: 1, 27 | child: ClipRRect( 28 | clipBehavior: Clip.antiAliasWithSaveLayer, 29 | borderRadius: BorderRadius.circular(borderRadius), 30 | child: Transform.scale(scale: _scale, child: Stack(fit: StackFit.expand, children: [ 31 | background ?? DecoratedBox(decoration: BoxDecoration(color: backColor ?? Colors.white)), 32 | foreground ?? const SizedBox(width: 0) 33 | ],)) 34 | ), 35 | ) 36 | ); 37 | } 38 | ), 39 | ) 40 | ); 41 | } 42 | } -------------------------------------------------------------------------------- /lib/widget/flexible_info_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:fluent_ui/fluent_ui.dart'; 2 | import 'package:flutter/material.dart' as material; 3 | import 'package:wsa_pacman/widget/fluent_info_bar.dart'; 4 | import 'package:wsa_pacman/widget/smooth_list_view.dart'; 5 | 6 | class FlexibleInfoBar extends StatelessWidget { 7 | 8 | const FlexibleInfoBar({ 9 | Key? key, 10 | required this.title, 11 | this.content, 12 | this.action, 13 | this.severity = InfoBarSeverity.info, 14 | this.style, 15 | this.onClose, 16 | }) : super(key: key); 17 | 18 | final InfoBarSeverity severity; 19 | final InfoBarThemeData? style; 20 | final Widget title; 21 | final Widget? content; 22 | final Widget? action; 23 | final void Function()? onClose; 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Flexible(child: LayoutBuilder( 28 | builder: (context, BoxConstraints constraints) { 29 | return FluentInfoBar( 30 | title: SizedBox( 31 | height: (constraints.maxHeight-25),// - (constraints.maxHeight-constr.maxHeight), 32 | child: material.Scaffold( 33 | backgroundColor: Colors.transparent, 34 | appBar: _PaddedTitle(DefaultTextStyle( 35 | style: FluentTheme.of(context).typography.bodyStrong ?? const TextStyle(), 36 | child: title, 37 | )), 38 | body: (content != null) ? SmoothListView(children: [DefaultTextStyle( 39 | style: FluentTheme.of(context).typography.body ?? const TextStyle(), 40 | child: content!, 41 | softWrap: true, 42 | )]) : null 43 | ) 44 | ), 45 | isLong: true, 46 | severity: severity, 47 | style: style, 48 | action: action, 49 | onClose: onClose, 50 | ); 51 | } 52 | )); 53 | } 54 | } 55 | 56 | 57 | class _PaddedTitle extends StatelessWidget implements PreferredSizeWidget { 58 | final Widget child; 59 | 60 | const _PaddedTitle(this.child); 61 | 62 | @override 63 | Widget build(BuildContext context) { 64 | double? infoBarPadding = InfoBarTheme.of(context).padding?.vertical; 65 | if (infoBarPadding != null) infoBarPadding /= 2; 66 | return Padding(padding: EdgeInsets.only(bottom: infoBarPadding ?? 10), child: child); 67 | } 68 | 69 | @override 70 | Size get preferredSize => const Size.fromHeight(double.maxFinite); 71 | } -------------------------------------------------------------------------------- /lib/widget/fluent_info_bar.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | import 'package:fluent_ui/fluent_ui.dart'; 3 | import 'package:flutter/foundation.dart'; 4 | 5 | class FluentInfoBar extends StatelessWidget { 6 | /// Creates an info bar. 7 | const FluentInfoBar({ 8 | Key? key, 9 | required this.title, 10 | this.content, 11 | this.action, 12 | this.severity = InfoBarSeverity.info, 13 | this.style, 14 | this.isLong = false, 15 | this.onClose, 16 | }) : super(key: key); 17 | 18 | /// The severity of this InfoBar. Defaults to [InfoBarSeverity.info] 19 | final InfoBarSeverity severity; 20 | 21 | /// The style applied to this info bar. If non-null, it's 22 | /// mescled with [ThemeData.infoBarThemeData] 23 | final InfoBarThemeData? style; 24 | 25 | final Widget title; 26 | final Widget? content; 27 | final Widget? action; 28 | 29 | /// Called when the close button is pressed. If this is null, 30 | /// there will be no close button 31 | final void Function()? onClose; 32 | 33 | /// If `true`, the info bar will be treated as long. 34 | /// 35 | /// ![Long InfoBar](https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/images/infobar-success-content-wrapping.png) 36 | final bool isLong; 37 | 38 | @override 39 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { 40 | super.debugFillProperties(properties); 41 | properties 42 | ..add(FlagProperty('long', value: isLong, ifFalse: 'short')) 43 | ..add(EnumProperty('severity', severity)) 44 | ..add(ObjectFlagProperty.has('onClose', onClose)) 45 | ..add(DiagnosticsProperty('style', style, ifNull: 'no style')); 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | assert(debugCheckHasFluentTheme(context)); 51 | assert(debugCheckHasFluentLocalizations(context)); 52 | final localizations = FluentLocalizations.of(context); 53 | final style = InfoBarTheme.of(context).merge(this.style); 54 | final icon = style.icon?.call(severity); 55 | final closeIcon = style.closeIcon; 56 | final title = DefaultTextStyle( 57 | style: FluentTheme.of(context).typography.bodyStrong ?? const TextStyle(), 58 | child: this.title, 59 | ); 60 | final content = () { 61 | if (this.content == null) return null; 62 | return DefaultTextStyle( 63 | style: FluentTheme.of(context).typography.body ?? const TextStyle(), 64 | child: this.content!, 65 | softWrap: true, 66 | ); 67 | }(); 68 | final action = () { 69 | if (this.action == null) return null; 70 | return ButtonTheme.merge( 71 | child: this.action!, 72 | data: ButtonThemeData.all(style.actionStyle), 73 | ); 74 | }(); 75 | return Container( 76 | decoration: style.decoration?.call(severity), 77 | padding: style.padding ?? const EdgeInsets.all(10), 78 | alignment: AlignmentDirectional.centerStart, 79 | child: Row( 80 | mainAxisSize: MainAxisSize.min, 81 | crossAxisAlignment: 82 | isLong ? CrossAxisAlignment.start : CrossAxisAlignment.center, 83 | children: [ 84 | if (icon != null) 85 | Padding( 86 | padding: const EdgeInsetsDirectional.only(end: 6.0), 87 | child: Icon(icon, color: style.iconColor?.call(severity)), 88 | ), 89 | if (isLong) 90 | Flexible( 91 | fit: FlexFit.loose, 92 | child: Column( 93 | mainAxisSize: MainAxisSize.min, 94 | crossAxisAlignment: CrossAxisAlignment.start, 95 | children: [ 96 | title, 97 | if (content != null) 98 | Padding( 99 | padding: const EdgeInsets.only(top: 6.0), 100 | child: content, 101 | ), 102 | if (action != null) 103 | Padding( 104 | padding: const EdgeInsets.only(top: 6.0), 105 | child: action, 106 | ), 107 | ], 108 | ), 109 | ) 110 | else 111 | Flexible( 112 | fit: FlexFit.loose, 113 | child: Wrap( 114 | crossAxisAlignment: WrapCrossAlignment.center, 115 | spacing: 6, 116 | children: [ 117 | title, 118 | if (content != null) content, 119 | if (action != null) action, 120 | ], 121 | ), 122 | ), 123 | if (closeIcon != null && onClose != null) 124 | Padding( 125 | padding: const EdgeInsetsDirectional.only(start: 10.0), 126 | child: Tooltip( 127 | message: localizations.closeButtonLabel, 128 | child: IconButton( 129 | icon: Icon(closeIcon, size: style.closeIconSize), 130 | onPressed: onClose, 131 | style: style.closeButtonStyle, 132 | ), 133 | ), 134 | ), 135 | ], 136 | ), 137 | ); 138 | } 139 | } -------------------------------------------------------------------------------- /lib/widget/move_window_nomax.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: camel_case_types 2 | 3 | import 'package:bitsdojo_window/bitsdojo_window.dart'; 4 | import 'package:flutter/widgets.dart'; 5 | 6 | ///The double click gesture detector adds a time overhead on any widget's click actions, this class only implements window dragging 7 | class _MoveWindowNoMaximize extends StatelessWidget { 8 | final bool dragBlocker; 9 | final Widget child; 10 | const _MoveWindowNoMaximize(this.dragBlocker, {Key? key, required this.child}) : super(key: key); 11 | @override 12 | Widget build(BuildContext context) => GestureDetector( 13 | child: child, 14 | behavior: dragBlocker ? HitTestBehavior.opaque : HitTestBehavior.translucent, 15 | onPanStart: dragBlocker ? (_){} : (_){appWindow.startDragging();} 16 | ); 17 | } 18 | 19 | class moveWindow extends _MoveWindowNoMaximize { 20 | ///Makes the window draggable on dragging the child view 21 | const moveWindow(Widget child, {Key? key}) : super(false, child: child, key: key); 22 | } 23 | 24 | class noMoveWindow extends _MoveWindowNoMaximize { 25 | ///Creates a non-draggable zone inside a draggable window 26 | const noMoveWindow(Widget child, {Key? key}) : super(true, child: child, key: key); 27 | } 28 | -------------------------------------------------------------------------------- /lib/widget/smooth_list_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:smooth_scroll_multiplatform/smooth_scroll_multiplatform.dart'; 2 | 3 | import 'package:flutter/gestures.dart'; 4 | import 'package:flutter/widgets.dart'; 5 | 6 | class SmoothListView extends DynMouseScroll { 7 | SmoothListView({ 8 | // Dynamic mouse scroll params 9 | super.key, 10 | super.durationMS = 380, 11 | super.scrollSpeed = 2, 12 | super.animationCurve = Curves.easeOutQuart, 13 | // ListView params 14 | Key? innerListViewKey, 15 | Axis scrollDirection = Axis.vertical, 16 | bool reverse = false, 17 | bool? primary, 18 | bool shrinkWrap = false, 19 | EdgeInsetsGeometry? padding, 20 | double? itemExtent, 21 | Widget? prototypeItem, 22 | bool addAutomaticKeepAlives = true, 23 | bool addRepaintBoundaries = true, 24 | bool addSemanticIndexes = true, 25 | double? cacheExtent, 26 | List children = const [], 27 | int? semanticChildCount, 28 | DragStartBehavior dragStartBehavior = DragStartBehavior.start, 29 | ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual, 30 | String? restorationId, 31 | Clip clipBehavior = Clip.hardEdge, 32 | }) : super( 33 | builder: (context, controller, physics) => ListView( 34 | key: innerListViewKey, 35 | scrollDirection: scrollDirection, 36 | reverse: reverse, 37 | controller: controller, 38 | primary: primary, 39 | physics: physics, 40 | shrinkWrap : shrinkWrap, 41 | padding: padding, 42 | itemExtent: itemExtent, 43 | prototypeItem: prototypeItem, 44 | addAutomaticKeepAlives: addAutomaticKeepAlives, 45 | addRepaintBoundaries: addRepaintBoundaries, 46 | addSemanticIndexes: addSemanticIndexes, 47 | cacheExtent: cacheExtent, 48 | children: children, 49 | semanticChildCount: semanticChildCount, 50 | dragStartBehavior: dragStartBehavior, 51 | keyboardDismissBehavior: keyboardDismissBehavior, 52 | restorationId: restorationId, 53 | clipBehavior: clipBehavior 54 | ) 55 | ); 56 | } -------------------------------------------------------------------------------- /lib/windows/win_info.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: non_constant_identifier_names 2 | 3 | import 'dart:ffi'; 4 | 5 | import 'package:ffi/ffi.dart'; 6 | import 'package:win32/win32.dart'; 7 | import 'package:wsa_pacman/windows/win_wmi.dart'; 8 | 9 | bool testFlag(int value, int attribute) => value & attribute == attribute; 10 | 11 | /// Represents the version number (e.g. 10.0) 12 | class WinVer { 13 | int major; 14 | int minor; 15 | WinVer._(this.major, this.minor); 16 | 17 | static late final String WIN_CAPTION = WinWMI.queryString('Caption', 'Win32_OperatingSystem') ?? ''; 18 | 19 | @override String toString() => '$major.$minor'; 20 | 21 | static late final WinVer version = (){ 22 | final versionInfo = calloc(); 23 | versionInfo.ref.dwOSVersionInfoSize = sizeOf(); 24 | 25 | try { 26 | final result = GetVersionEx(versionInfo); 27 | return (result != 0) ? WinVer._(versionInfo.ref.dwMajorVersion, versionInfo.ref.dwMinorVersion) : WinVer._(0, 0); 28 | } finally {free(versionInfo);} 29 | }(); 30 | 31 | static bool isAtLeast(int major, int minor) => version.major > major || version.major == major && version.minor >= minor; 32 | 33 | static late final bool isWindowsXPOrGreater = isAtLeast(5, 1); 34 | static late final bool isWindowsVistaOrGreater = isAtLeast(6, 0); 35 | static late final bool isWindows7OrGreater = isAtLeast(6, 1); 36 | static late final bool isWindows8OrGreater = isAtLeast(6, 2); 37 | static late final bool isWindows10OrGreater = isAtLeast(10, 0); 38 | static late final bool isWindows11OrGreater = isAtLeast(10, 1) || 39 | (isAtLeast(10, 0) && !WIN_CAPTION.contains(RegExp(r'(^|\s)(Windows 10x?|Server 2016)($|\s)', caseSensitive: false)) ); 40 | } -------------------------------------------------------------------------------- /lib/windows/win_path.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | // Demonstrates usage of various shell APIs to retrieve known folder locations 6 | 7 | import 'dart:ffi'; 8 | import 'dart:io'; 9 | import 'package:ffi/ffi.dart'; 10 | import 'package:win32/win32.dart'; 11 | 12 | class WinPath { 13 | /// Get the path of the temporary directory (typically %TEMP%) 14 | static late String temp = Directory.systemTemp.absolute.path; 15 | 16 | /// Sub-directory inside %TEMP% to use by the application 17 | static late String tempSubdir = Directory.systemTemp.createTempSync("WSA-PacMan-").absolute.path; 18 | 19 | /// Get the desktop path 20 | static late String desktop = (){ 21 | final appsFolder = GUIDFromString(FOLDERID_Desktop); 22 | final ppszPath = calloc(); 23 | 24 | try { 25 | final hr = 26 | SHGetKnownFolderPath(appsFolder, KF_FLAG_DEFAULT, NULL, ppszPath); 27 | 28 | if (FAILED(hr)) { 29 | throw WindowsException(hr); 30 | } 31 | 32 | final path = ppszPath.value.toDartString(); 33 | return path; 34 | } finally { 35 | free(appsFolder); 36 | free(ppszPath); 37 | } 38 | }(); 39 | } 40 | -------------------------------------------------------------------------------- /lib/windows/win_pkg.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: constant_identifier_names, non_constant_identifier_names 2 | 3 | import 'dart:ffi'; 4 | import 'dart:io'; 5 | import 'dart:typed_data'; 6 | import 'package:base32/encodings.dart'; 7 | import 'package:charset/charset.dart'; 8 | import 'package:crypto/crypto.dart'; 9 | 10 | import 'package:base32/base32.dart'; 11 | import 'package:ffi/ffi.dart'; 12 | import 'package:win32/win32.dart'; 13 | 14 | import '../utils/string_utils.dart'; 15 | 16 | 17 | const _INITIAL_OUTPUT_BUFFER_CHARS = 256; 18 | 19 | class WinPkg { 20 | static String getPublisherId(String publisher) { 21 | return base32.encode(Uint8List.fromList(sha256.convert((utf16.encoder as Utf16Encoder).encodeUtf16Le(publisher)).bytes.sublist(0, 8)), encoding: Encoding.crockford).toLowerCase(); 22 | } 23 | 24 | static String? getPackageFamilyName(String fullName) { 25 | final lpName = fullName.toNativeUtf16(); 26 | var lpFamilyName = malloc(_INITIAL_OUTPUT_BUFFER_CHARS).cast(); 27 | final lpBufferLenght = malloc()..value = _INITIAL_OUTPUT_BUFFER_CHARS; 28 | 29 | try { 30 | int exitCode = PackageFamilyNameFromFullName(lpName, lpBufferLenght, lpFamilyName); 31 | if (exitCode == ERROR_INSUFFICIENT_BUFFER) { 32 | free(lpFamilyName); 33 | lpFamilyName = malloc(lpBufferLenght.value).cast(); 34 | PackageFamilyNameFromFullName(lpName, lpBufferLenght, lpFamilyName); 35 | } 36 | return lpFamilyName.toDartString(); 37 | } 38 | finally { 39 | free(lpName); 40 | free(lpFamilyName); 41 | free(lpBufferLenght); 42 | } 43 | } 44 | } 45 | 46 | 47 | class WinPkgInfo { 48 | late final String name; 49 | late final String publisherId; 50 | late final String version; 51 | late final String architecture; 52 | 53 | String get fullName => "${name}_${version}_${architecture}__$publisherId"; 54 | String get familyName => "${name}_$publisherId"; 55 | void parseManifestExtras(String manifest) {} 56 | 57 | WinPkgInfo(String manifest) { 58 | try { 59 | String? identity = RegExp(r'<\s*Identity[^">]*("[^"]*"[^">]*)*>', multiLine: true).firstMatch(manifest)?.group(0)?.replaceAll('\n', ' '); 60 | name = identity?.find(r'\s+Name\s*=\s*"([^"]*)', 1) ?? 'UNKNOWN_APP_NAME'; 61 | String? publisher = identity?.find(r'\s+Publisher\s*=\s*"([^"]*)', 1); 62 | publisherId = (publisher != null) ? WinPkg.getPublisherId(publisher) : 'UNKNOWN_PUBLISHER_ID'; 63 | version = identity?.find(r'\s+Version\s*=\s*"([^"]*)', 1) ?? 'UNKNOWN_VERSION'; 64 | architecture = identity?.find(r'\s+ProcessorArchitecture\s*=\s*"([^"]*)', 1) ?? 'UNKNOWN_ARCHITECTURE'; 65 | parseManifestExtras(manifest); 66 | } 67 | catch(e) {/**/} 68 | } 69 | 70 | WinPkgInfo.fromSystemPath(String systemPath) : this(_tryReadManifest("$systemPath\\AppxManifest.xml")); 71 | 72 | static String _tryReadManifest(String manifestFile) { 73 | try {return File(manifestFile).readAsStringSync();} 74 | catch(_) {return "";} 75 | } 76 | } -------------------------------------------------------------------------------- /lib/windows/win_reg.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: constant_identifier_names, non_constant_identifier_names, curly_braces_in_flow_control_structures 2 | 3 | import 'dart:developer'; 4 | import 'dart:ffi'; 5 | 6 | import 'package:ffi/ffi.dart'; 7 | import 'package:win32/win32.dart'; 8 | 9 | const _MAX_ITEMLENGTH = 1024; 10 | 11 | extension WinRegStringExtension on String { 12 | static final RegExp _KEY_PATH_NORMALIZER = RegExp(r'[\\]*(.*)'); 13 | String? get normalizedRegKey => _KEY_PATH_NORMALIZER.firstMatch(this)?.group(1); 14 | } 15 | 16 | enum RegHKey { 17 | HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_PERFORMANCE_DATA, HKEY_PERFORMANCE_TEXT, 18 | HKEY_PERFORMANCE_NLSTEXT, HKEY_CURRENT_CONFIG, HKEY_DYN_DATA, HKEY_CURRENT_USER_LOCAL_SETTINGS 19 | } 20 | 21 | extension on RegHKey { 22 | int get value {switch(this) { 23 | case RegHKey.HKEY_CLASSES_ROOT: return HKEY_CLASSES_ROOT; 24 | case RegHKey.HKEY_CURRENT_USER: return HKEY_CURRENT_USER; 25 | case RegHKey.HKEY_LOCAL_MACHINE: return HKEY_LOCAL_MACHINE; 26 | case RegHKey.HKEY_USERS: return HKEY_USERS; 27 | case RegHKey.HKEY_PERFORMANCE_DATA: return HKEY_PERFORMANCE_DATA; 28 | case RegHKey.HKEY_PERFORMANCE_TEXT: return HKEY_PERFORMANCE_TEXT; 29 | case RegHKey.HKEY_PERFORMANCE_NLSTEXT: return HKEY_PERFORMANCE_NLSTEXT; 30 | case RegHKey.HKEY_CURRENT_CONFIG: return HKEY_CURRENT_CONFIG; 31 | case RegHKey.HKEY_DYN_DATA: return HKEY_DYN_DATA; 32 | case RegHKey.HKEY_CURRENT_USER_LOCAL_SETTINGS: return HKEY_CURRENT_USER_LOCAL_SETTINGS; 33 | }} 34 | } 35 | 36 | class RegistryKeyValuePair { 37 | final String key; 38 | final String value; 39 | 40 | const RegistryKeyValuePair(this.key, this.value); 41 | } 42 | 43 | class RegValue { 44 | RegValue._create(this.type, this.value); 45 | String value; 46 | int type; 47 | } 48 | 49 | class WinReg { 50 | static RegValue? getString(RegHKey hKey, String keyPath, String? valName, {bool noExpand = false}) { 51 | String? keyPathN = keyPath.normalizedRegKey; 52 | if (keyPathN == null) return null; 53 | 54 | final lpKey = keyPathN.toNativeUtf16(); 55 | final lpValue = (valName != null && valName.isNotEmpty) ? valName.toNativeUtf16() : nullptr; 56 | final lpType = calloc(); 57 | final lpData = calloc(_MAX_ITEMLENGTH); 58 | final lpcbData = calloc()..value = _MAX_ITEMLENGTH; 59 | 60 | int flags = RRF_RT_ANY; 61 | if (noExpand) flags |= RRF_NOEXPAND; 62 | 63 | try { 64 | final status = RegGetValue(hKey.value, lpKey, lpValue, flags, lpType, lpData, lpcbData); 65 | 66 | switch (status) { 67 | case ERROR_SUCCESS: 68 | int type = lpType.value; 69 | if (type != REG_SZ && type != REG_EXPAND_SZ && type != REG_MULTI_SZ) { 70 | log('win_reg: Non-string content; type: $type'); 71 | return null; 72 | } 73 | log('win_reg: value type: $type'); 74 | return RegValue._create(type, lpData.cast().toDartString()); 75 | 76 | case ERROR_MORE_DATA: 77 | log('win_reg: An item required more than $_MAX_ITEMLENGTH bytes'); 78 | return null; 79 | //throw Exception('An item required more than $_MAX_ITEMLENGTH bytes.'); 80 | 81 | case ERROR_NO_MORE_ITEMS: 82 | return null; 83 | 84 | default: 85 | log('win_reg: Unknown error'); 86 | return null; 87 | //throw Exception('unknown error'); 88 | } 89 | } finally { 90 | free(lpKey); 91 | free(lpValue); 92 | free(lpType); 93 | free(lpData); 94 | free(lpcbData); 95 | } 96 | } 97 | 98 | static int? openKeyLp(RegHKey hKey, Pointer lpKeyPath) { 99 | Pointer lpKey = calloc(); 100 | try { 101 | int result = RegOpenKeyEx(hKey.value, lpKeyPath, 0, KEY_READ, lpKey); 102 | return result == ERROR_SUCCESS ? lpKey.value : null; 103 | } finally { 104 | free(lpKey); 105 | } 106 | } 107 | 108 | static int? openKey(RegHKey hKey, String keyPath) { 109 | String? keyPathN = keyPath.normalizedRegKey; 110 | if (keyPathN == null) return null; 111 | final lpKeyPath = keyPathN.toNativeUtf16(); 112 | 113 | try { 114 | return openKeyLp(hKey, lpKeyPath); 115 | } finally { 116 | free(lpKeyPath); 117 | } 118 | } 119 | 120 | static List listSubkeys(int key, [int? knownSize]) { 121 | int actualSize = knownSize != null ? knownSize + 1 : MAX_PATH; 122 | LPWSTR subkeyName = malloc(actualSize).cast(); 123 | Pointer subkeyNameSize = malloc()..value = actualSize; 124 | 125 | try { 126 | return [...() sync* {for (int i = 0;;i++) { 127 | int result = RegEnumKeyEx(key, i, subkeyName, subkeyNameSize, nullptr, nullptr, nullptr, nullptr); 128 | if (result == ERROR_NO_MORE_ITEMS) break; // All subkeys have been enumerated 129 | else if (result != ERROR_SUCCESS) { 130 | log("Failed to enumerate subkey. Error code: $result"); 131 | continue; 132 | } 133 | subkeyNameSize.value = actualSize; 134 | yield subkeyName.toDartString(); 135 | }}()]; 136 | } 137 | finally { 138 | free(subkeyNameSize); 139 | free(subkeyName); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /lib/windows/win_wmi.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: constant_identifier_names, non_constant_identifier_names 2 | 3 | import 'dart:developer'; 4 | import 'dart:ffi'; 5 | 6 | import 'package:ffi/ffi.dart'; 7 | import 'package:win32/win32.dart'; 8 | 9 | /// Call WMI queries 10 | /// The COM library is never closed (TODO should change?) 11 | class WinWMI { 12 | 13 | static const String _namespace = r'ROOT\CIMV2'; 14 | static int _failPoint = 0; 15 | 16 | static String? queryString(String valName, String wmiClass) { 17 | IWbemServices? service = _service; 18 | if (service == null) return null; 19 | 20 | final pEnumerator = calloc>(); 21 | IEnumWbemClassObject? enumerator; 22 | 23 | try { 24 | // For example, query for all the running processes 25 | int hr = service.execQuery(TEXT('WQL'), TEXT('SELECT $valName FROM $wmiClass'), 26 | WBEM_GENERIC_FLAG_TYPE.WBEM_FLAG_FORWARD_ONLY | WBEM_GENERIC_FLAG_TYPE.WBEM_FLAG_RETURN_IMMEDIATELY, nullptr, pEnumerator); 27 | 28 | if (FAILED(hr)) { 29 | log(WindowsException(hr).toString(), level: 1000); 30 | free(pEnumerator); 31 | return null; 32 | } else { 33 | enumerator = IEnumWbemClassObject(pEnumerator.cast()); 34 | 35 | final uReturn = calloc(); 36 | 37 | if (enumerator.ptr.address > 0) { 38 | final pClsObj = calloc(); 39 | hr = enumerator.next(WBEM_TIMEOUT_TYPE.WBEM_INFINITE, 1, pClsObj.cast(), uReturn); 40 | 41 | // Break out of the while loop if we've run out of processes to inspect 42 | if (uReturn.value == 0) { 43 | free(pClsObj); 44 | return null; 45 | } 46 | 47 | final clsObj = IWbemClassObject(pClsObj.cast()); 48 | 49 | final vtProp = calloc(); 50 | hr = clsObj.get(TEXT(valName), 0, vtProp, nullptr, nullptr); 51 | String? value = SUCCEEDED(hr) ? vtProp.ref.bstrVal.toDartString() : null; 52 | 53 | VariantClear(vtProp); 54 | free(vtProp); 55 | clsObj.release(); 56 | 57 | return value; 58 | } 59 | } 60 | } 61 | finally { 62 | enumerator?.release() ?? free(pEnumerator); 63 | } 64 | } 65 | 66 | static IWbemServices? get _service => __serviceResult ?? _initService(); 67 | static IWbemServices? __serviceResult; 68 | 69 | static IWbemServices? _initService() { 70 | if (__serviceResult != null) return __serviceResult; 71 | int hr = 0; 72 | 73 | if (_failPoint < 1) { 74 | hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 75 | if (FAILED(hr)) { 76 | log(WindowsException(hr).toString(), level: 1000); 77 | return null; 78 | } 79 | } 80 | 81 | if (_failPoint < 1) _failPoint = 1; 82 | 83 | // Initialize security model 84 | if (_failPoint < 2) { 85 | hr = CoInitializeSecurity(nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, // Impersonation 86 | nullptr, EOLE_AUTHENTICATION_CAPABILITIES.EOAC_NONE, nullptr); 87 | 88 | if (FAILED(hr)) { 89 | log(WindowsException(hr).toString(), level: 1000); 90 | CoUninitialize(); 91 | return null; 92 | } 93 | } 94 | 95 | if (_failPoint < 2) _failPoint = 2; 96 | 97 | // Obtain the initial locator to Windows Management 98 | // on a particular host computer. 99 | final pLoc = IWbemLocator(calloc()); 100 | 101 | final clsid = malloc()..ref.setGUID(CLSID_WbemLocator); 102 | final iid = malloc()..ref.setGUID(IID_IWbemLocator); 103 | 104 | hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, iid, pLoc.ptr.cast()); 105 | 106 | if (FAILED(hr)) { 107 | log(WindowsException(hr).toString(), level: 1000); 108 | 109 | pLoc.release(); 110 | free(clsid); 111 | free(iid); 112 | CoUninitialize(); 113 | return null; 114 | } 115 | 116 | final proxy = calloc>(); 117 | 118 | // Connect to the root\cimv2 namespace with the 119 | // current user and obtain pointer pSvc 120 | // to make IWbemServices calls. 121 | hr = pLoc.connectServer(TEXT(_namespace), nullptr, nullptr, nullptr, NULL, nullptr, nullptr, proxy); 122 | 123 | if (FAILED(hr)) { 124 | log(WindowsException(hr).toString(), level: 1000); 125 | 126 | pLoc.release(); 127 | free(clsid); 128 | free(iid); 129 | free(proxy); 130 | CoUninitialize(); 131 | return null; // Program has failed. 132 | } 133 | 134 | log(r'Connected to ROOT\CIMV2 WMI namespace'); 135 | 136 | return __serviceResult = IWbemServices(proxy.cast()); 137 | 138 | // Set the IWbemServices proxy so that impersonation 139 | // of the user (client) occurs. 140 | /*hr = CoSetProxyBlanket( 141 | proxy.value, // the proxy to set 142 | RPC_C_AUTHN_WINNT, // authentication service 143 | RPC_C_AUTHZ_NONE, // authorization service 144 | nullptr, // Server principal name 145 | RPC_C_AUTHN_LEVEL_CALL, // authentication level 146 | RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level 147 | nullptr, // client identity 148 | EOLE_AUTHENTICATION_CAPABILITIES.EOAC_NONE // proxy capabilities 149 | ); 150 | 151 | if (FAILED(hr)) { 152 | final exception = WindowsException(hr); 153 | print(exception.toString()); 154 | pSvc.Release(); 155 | pLoc.Release(); 156 | CoUninitialize(); 157 | throw exception; // Program has failed. 158 | }*/ 159 | } 160 | } -------------------------------------------------------------------------------- /lib/windows/wsa_status.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: non_constant_identifier_names 2 | 3 | import 'package:ffi/ffi.dart'; 4 | import 'package:win32/win32.dart'; 5 | import 'package:wsa_pacman/windows/nt_io.dart'; 6 | import 'package:wsa_pacman/windows/win_io.dart'; 7 | import 'package:wsa_pacman/windows/win_reg.dart'; 8 | 9 | class WSAStatus { 10 | static late final _WSA_CLIENT_MUTEX = TEXT(r"{42CEB0DF-325A-4FBE-BBB6-C259A6C3F0BB}"); 11 | static LPWSTR REG_VOLATILE_STORE = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\HostComputeService\\VolatileStore\\ComputeSystem\\".normalizedRegKey!.toNativeUtf16(); 12 | static int? REG_VOLATILE_STORE_KEY; 13 | static String? WSA_VM_UUID; 14 | 15 | /// Checks if WSA is booted (With this status, it may still be in sleep mode) 16 | static bool get isBooted => WinIO.findMutexWstr(_WSA_CLIENT_MUTEX); 17 | 18 | /// Checks if WSA is running, if booted but not running, it's in sleep mode 19 | static bool get isRunning { 20 | REG_VOLATILE_STORE_KEY ??= WinReg.openKeyLp(RegHKey.HKEY_LOCAL_MACHINE, REG_VOLATILE_STORE); 21 | int? sessionId = NtIO.SESSION_ID; 22 | if (REG_VOLATILE_STORE_KEY == null || sessionId == null) return false; 23 | String? wsaVmUUID = WSA_VM_UUID; 24 | List runningVMs = wsaVmUUID == null ? WinReg.listSubkeys(REG_VOLATILE_STORE_KEY!, 36) : [wsaVmUUID]; 25 | for (String uuid in runningVMs) { 26 | bool isSubsystemVMRunning = NtIO.openSection("\\Sessions\\$sessionId\\BaseNamedObjects\\WSL\\$uuid\\latte\\gralloc_0", false); 27 | if (isSubsystemVMRunning) { 28 | WSA_VM_UUID = uuid; 29 | return true; 30 | } 31 | } 32 | WSA_VM_UUID = null; 33 | return false; 34 | } 35 | } -------------------------------------------------------------------------------- /locale/ar.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@locale": "ar", 3 | "@locale_desc": {"description": "Arabic [ar_EG]"}, 4 | "locale_desc": "العربية", 5 | "@locale_system": {"description": "Describes the system locale"}, 6 | "locale_system": "النظام", 7 | 8 | 9 | "btn_boot": "تشغيل", 10 | "btn_auth": "إعادة المصادقة", 11 | "btn_dev_settings": "خيارات المطور", 12 | "btn_switch_on": "مفعل", 13 | "btn_switch_off": "مغلق", 14 | 15 | 16 | "status_subtext_winver_10": "ويندوز 10", 17 | "status_subtext_winver_older": "إصدار ويندوز أقدم", 18 | 19 | 20 | "status_unsupported": "حزمة WSA غير مثبتة", 21 | "status_unsupported_desc": "تم العثور على إصدار {windowsVersion} و لم يثبت WSA ; و هذا التطبيق يعتمد على WSA, و التي تثبت على ويندوز 11 فقط", 22 | "status_unauthorized": "غير مصرح به", 23 | "status_unauthorized_desc": "تم رفض التصريح الإصداري أو الغاءه؛ اضغط على الزر الأول، اختر 'دائما السماح'، ثم اضغط على 'السماح'؛ إذا لم يظهر مربع حوار، فتح خيارات المطور وعطل وإعادة تمكين 'تصحيح USB'", 24 | "status_missing": "حزمة WSA غير مثبتة", 25 | "status_missing_desc": "حزمة WSA غير موجودة; و هذا التطبيق يعتمد على WSA, برجاء تحميل نظام اندرويد لويندوز او متجر امازون من متجر مايكروسوفت", 26 | "status_unknown": "جاري الاتصال", 27 | "status_unknown_desc": "في انتظار الاتصال بWSA", 28 | "status_starting": "جاري التشغيل", 29 | "status_starting_desc": "جاري تشغيل WSA, برجاء الانتظار", 30 | "status_arrested": "غير مفعل", 31 | "status_arrested_desc": "WSA غير مفعل", 32 | "status_offline": "غير متصل", 33 | "status_offline_desc": "لم يمكن الاتصال بWSA: يمكن ان يكون وضع المطور غير مفعل, او تم تحديد المخرج الخاطىء", 34 | "status_disconnected": "لا يمكن الاتصال", 35 | "status_disconnected_desc": "لا يمكن عمل اتصال لWSA لاسباب غير معلومه", 36 | "status_connected": "متصل", 37 | "status_connected_desc": "تم الاتصال بنجاح", 38 | 39 | 40 | "screen_wsa": "مدير حزم الWSA", 41 | "screen_settings": "الضبط", 42 | 43 | 44 | "wsa_manage": "إدارة الاندرويد", 45 | "wsa_manage_app": "إدارة التطبيقات", 46 | "wsa_manage_settings": "إدارة الضبط", 47 | 48 | 49 | "settings_port": "مدخل الWSA", 50 | "settings_ip": "عنوان الIP الخاص بWSA", 51 | "settings_autostart": "تفعبل تلقائي لWSA قبل التثبيت", 52 | "settings_timeout": "مهلة ({seconds} ثواني)", 53 | "settings_language": "اللغة", 54 | "settings_option_generic_system": "النظام", 55 | "settings_option_generic_disabled": "غير مفعل", 56 | 57 | 58 | "theme_mode": "وضع السمات", 59 | "theme_mode_dark": "داكن", 60 | "theme_mode_light": "ساطع", 61 | "theme_mica": "شفافية النافذة", 62 | "theme_mica_full": "كامل", 63 | "theme_mica_partial": "جزئي", 64 | "theme_icon_adaptive": "ايقونات متكيفة", 65 | "theme_icon_adaptive_squircle": "مربع منحني", 66 | "theme_icon_adaptive_circle": "دائري", 67 | "theme_icon_adaptive_rounded_square": "مربع مستدير", 68 | 69 | 70 | "installer_message": "هل تريد تثبيت هذا التطبيق؟", 71 | "installer_info_version": "الإصدار: {appVersion}", 72 | "installer_info_version_change": "الإصدار: {appVersionOld} => {appVersionNew}", 73 | "installer_info_package": "الحزمة: {appPackage}", 74 | "installer_installing": "جاري تثبيث {appTitle}...", 75 | "installer_installed": "تم تثبيت {appTitle} بنجاح", 76 | "installer_fail": "لم يتم تثبيت {appTitle}", 77 | "installer_error_nomsg": "فشل التثبيت, لكن بلا أخطاء", 78 | "installer_error_timeout": "انتهت مهلة التثبيت، لقد توقف العميل عن الانتظار، لكن قد يظل التثبيت قيد التقدم في الخلفية...", 79 | "installer_warning_dirty": "يلزم تنظيف يدوي للملفات في الدليل ‹{tempDir}›", 80 | "installer_btn_starting": "يتم التشغيل...", 81 | "installer_btn_loading": "تحميل...", 82 | "installer_btn_cancel": "إلغاء", 83 | "installer_btn_install": "تثبيت", 84 | "installer_btn_reinstall": "إعادة التثبيت", 85 | "installer_btn_update": "تحديث", 86 | "installer_btn_downgrade": "الرجوع إلى إصدار قديم(غير آمن)", 87 | "installer_btn_dismiss": "تم", 88 | "installer_btn_open": "فتح التطبيق", 89 | "installer_btn_checkbox_shortcut": "عمل اختصار على سطح المكتب", 90 | 91 | 92 | "android_permission_none": "لا يطلب اي اذونات", 93 | "android_permission_admin": "يدير الجهاز كمشرف", 94 | "android_permission_admin_brick": "يلغي تفعيل الجهاز او يعيد ضبطه عن بعد", 95 | "android_permission_admin_lock": "قفل الجهاز عن بعد", 96 | "android_permission_storage": "الملفات و الوسائط", 97 | "android_permission_microphone": "الميكروفون", 98 | "android_permission_camera": "الكاميرا", 99 | "android_permission_location": "الموقع", 100 | "android_permission_phone": "الهاتف", 101 | "android_permission_call_log": "سجلات المكالمات", 102 | "android_permission_sms": "الرسائل", 103 | "android_permission_contacts": "جهات الاتصال", 104 | "android_permission_calendar": "التقويم", 105 | "android_permission_activity_recognition": "الانشطة البدنية", 106 | "android_permission_sensors": "مستشعرات الجهاز", 107 | "android_permission_sensors_body": "مستشعرات البدن", 108 | "android_permission_nearby_devices": "تحديد الاجهزة القريبة" 109 | } 110 | -------------------------------------------------------------------------------- /locale/fa.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@locale": "fa", 3 | "@locale_desc": {"description": "Farsi (Persian) [fa_IR]"}, 4 | "locale_desc": "فارسی", 5 | "@locale_system": {"description": "Describes the system locale"}, 6 | "locale_system": "سیستم", 7 | 8 | 9 | "btn_boot": "روشن کردن", 10 | "btn_auth": "تأیید دوباره", 11 | "btn_dev_settings": "گزینه‌های توسعه‌دهنده", 12 | "btn_switch_on": "روشن", 13 | "btn_switch_off": "خاموش", 14 | 15 | 16 | "status_subtext_winver_10": "ویندوز 10", 17 | "status_subtext_winver_older": "نسخه قدیمی ویندوز", 18 | 19 | 20 | "status_unsupported": "WSA نصب نشده", 21 | "status_unsupported_desc": "{windowsVersion} شناسایی شد و یافت نشد. این برنامه به WSA وابسته است که به طور رسمی فقط در ویندوز 11 پشتیبانی می شود", 22 | "status_unauthorized": "غیر مجاز", 23 | "status_unauthorized_desc": "تأیید توسعه دهنده رد شده یا لغو شده است؛ لطفا دکمه اول را کلیک کنید، «همیشه مجاز» را انتخاب کرده و روی «مجاز» کلیک کنید؛ اگر پنجره پاپ آپ نشان ندهد، گزینه های توسعه دهنده را باز کرده و غیر فعال کردن و دوباره فعال کردن 'دیباگ USB'", 24 | "status_missing": "WSA نصب نشده", 25 | "status_missing_desc": "WSA یافت نشد. این برنامه وابسته به WSA است، لطفا زیرسیستم ویندوز را برای اندروید (یا اپ استور آمازون) از Microsoft Store را نصب کنید", 26 | "status_unknown": "در حال اتصال", 27 | "status_unknown_desc": "در انتظار برقراری اتصال WSA...", 28 | "status_starting": "شروع ...", 29 | "status_starting_desc": "WSA در حال شروع است، لطفا منتظر بمانید...", 30 | "status_arrested": "دستگیر شد", 31 | "status_arrested_desc": "WSA خاموش شد", 32 | "status_offline": "آفلاین", 33 | "status_offline_desc": "اتصال با WSA امکان‌پذیر نیست: یا حالت برنامه‌نویس و اشکال‌زدایی USB غیرفعال هستند یا پورت اشتباهی مشخص شده است.", 34 | "status_disconnected": "قطع شده", 35 | "status_disconnected_desc": "اتصال WSA به دلایل نامعلومی برقرار نشد", 36 | "status_connected": "وصل شده", 37 | "status_connected_desc": "با موفقیت به WSA متصل شد، سیستم ها کار میکند", 38 | 39 | 40 | "screen_wsa": "مدیریت بسته WSA", 41 | "screen_settings": "تنظیمان", 42 | 43 | 44 | "wsa_manage": "مدیریت اندروید", 45 | "wsa_manage_app": "مدیریت برنامه ها", 46 | "wsa_manage_settings": "مدیریت تنظیمات", 47 | 48 | 49 | "settings_port": "پورت WSA", 50 | "settings_ip": "آدری آی پی WSA", 51 | "settings_autostart": "قبل از نصب WSA را به صورت خودکار راه اندازی شود", 52 | "settings_timeout": "زمان مجاز ({seconds} ثانیه)", 53 | "settings_language": "زبان", 54 | "settings_option_generic_system": "سیستم", 55 | "settings_option_generic_disabled": "غیرفعال", 56 | 57 | 58 | "theme_mode": "نوع زمینه", 59 | "theme_mode_dark": "تاریک", 60 | "theme_mode_light": "روشن", 61 | "theme_mica": "شفافیت پنجره ها", 62 | "theme_mica_full": "کامل", 63 | "theme_mica_partial": "جزئي", 64 | "theme_icon_adaptive": "سازگارسازی آیکون", 65 | "theme_icon_adaptive_squircle": "مربع", 66 | "theme_icon_adaptive_circle": "دایره", 67 | "theme_icon_adaptive_rounded_square": "گوشه های کرد", 68 | 69 | 70 | "installer_message": "آیا از نصب این برنامه اطمینان دارید؟", 71 | "installer_info_version": "تسخه: {appVersion}", 72 | "installer_info_version_change": "نسخه: {appVersionOld} => {appVersionNew}", 73 | "installer_info_package": "بسته: {appPackage}", 74 | "installer_installing": "در حال نصب {appTitle}...", 75 | "installer_installed": "برنامه {appTitle} نصب شد", 76 | "installer_fail": "برنامه {appTitle} نصب نشد.", 77 | "installer_error_nomsg": "نصب انجام نشد، اما خطایی هم رخ نداد", 78 | "installer_error_timeout": "زمان نصب تمام شد، مشتری نیازی به صبر ندارد، اما فرایند هنوز ممکن است در پسزمینه داشته باشد...", 79 | "installer_warning_dirty": "شاید نیاز به پاک کردن دستی فایل‌ها در پوشه ‌«{tempDir}» باشد", 80 | "installer_btn_starting": "شروع...", 81 | "installer_btn_loading": "بارگذاری...", 82 | "installer_btn_cancel": "لغو", 83 | "installer_btn_install": "نصب", 84 | "installer_btn_reinstall": "نصب مجدد", 85 | "installer_btn_update": "بروزرسانی", 86 | "installer_btn_downgrade": "Downgrade (امن نیست)", 87 | "installer_btn_dismiss": "رد کردن", 88 | "installer_btn_open": "باز کردن", 89 | "installer_btn_checkbox_shortcut": "ساخت میانبر در دسکتاپ", 90 | 91 | 92 | "android_permission_none": "هیچ مجوزی لازم نیست", 93 | "android_permission_admin": "مدیریت دستگاه", 94 | "android_permission_admin_brick": "غیرفعال یا بازنشانی دستگاه از راه دور", 95 | "android_permission_admin_lock": "قفل دستگاه از راه دور", 96 | "android_permission_storage": "فایل ها و رسانه ها", 97 | "android_permission_microphone": "میکروفون", 98 | "android_permission_camera": "دوربین", 99 | "android_permission_location": "موقعیت مکانی", 100 | "android_permission_phone": "تلفن", 101 | "android_permission_call_log": "تماس ها", 102 | "android_permission_sms": "پیام ها", 103 | "android_permission_contacts": "مخاطبین", 104 | "android_permission_calendar": "تقویم", 105 | "android_permission_activity_recognition": "فعالیت های بدنی", 106 | "android_permission_sensors": "سنسور دستگاه", 107 | "android_permission_sensors_body": "سنسور بدن", 108 | "android_permission_nearby_devices": "پیدا کردن دستگاه های نزدیک" 109 | } -------------------------------------------------------------------------------- /locale/he.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@README_1": "The en.arb file is a template for other files", 3 | "@@README_2": "For other languages, entries starting with @ and @@ are not needed, except @@locale", 4 | "@@README_3": "Country-specific locales (eg. 'en_GB') need a fallback locale (eg. 'en') to exist", 5 | 6 | 7 | "@@locale": "he", 8 | "@locale_desc": {"description": "Hebrew [he_IL]"}, 9 | "locale_desc": "עברית", 10 | "locale_system": "מערכת", 11 | 12 | 13 | "btn_boot": "הפעל", 14 | "btn_auth": "אימות מחדש", 15 | "btn_dev_settings": "אפשרויות מפתח", 16 | "btn_switch_on": "פועל", 17 | "btn_switch_off": "כבוי", 18 | 19 | "status_subtext_winver_10": "Windows 10", 20 | "status_subtext_winver_older": "גרסת Windows ישנה יותר", 21 | 22 | 23 | "status_unsupported": "WSA לא מותקן", 24 | "status_unsupported_desc": "זוהתה מערכת הפעלה {windowsVersion} WSA ולא נמצא; תוכנה זו תלויה ב WSA, אשר נתמך רשמית רק ב-Windows 11.", 25 | "status_unauthorized": "לא מאושר", 26 | "status_unauthorized_desc": "האימות לפיתוח נדחה או בוטל; לחץ על הכפתור הראשון, בחר תמיד מאשר ולחץ על מאשר; אם לא מופיע חלון קופץ, פתח אפשרויות מפתח וכבה ואפס הפעלה של ניפוי USB", 27 | "status_missing": "WSA לא מותקן", 28 | "status_missing_desc": "WSA לא נמצא; תוכנה זו תלויה ב-WSA, התקן את תת-המערכת של וינדוס עבור Android (לדוגמה מ-Microsoft Store)", 29 | "status_unknown": "מתחבר", 30 | "status_unknown_desc": "ממתין ליצירת חיבור עם WSA...", 31 | "status_starting": "מפעיל", 32 | "status_starting_desc": "מפעיל את WSA, אנא המתן...", 33 | "status_arrested": "נעצר", 34 | "status_arrested_desc": "WSA כבוי", 35 | "status_offline": "Offline", 36 | "status_offline_desc": "לא ניתן להתחבר אל WSA: מצב מפתח ואיתור באגים ב-USB מושבתים או שצויין Port שגוי", 37 | "status_disconnected": "מנותק", 38 | "status_disconnected_desc": "לא ניתן היה ליצור חיבור עם WSA מסיבה לא ידועה", 39 | "status_connected": "מחובר", 40 | "status_connected_desc": "מחובר בהצלחה ל-WSA, כל המערכות עוברות.", 41 | 42 | 43 | "screen_wsa": "WSA PacMan - מנהל חבילות ל-WSA", 44 | "screen_settings": "הגדרות", 45 | 46 | 47 | "wsa_manage": "ניהול הגדרות האנדרואיד", 48 | "wsa_manage_app": "נהל אפליקציות", 49 | "wsa_manage_settings": "נהל הגדרות", 50 | 51 | 52 | "settings_port": "WSA Port", 53 | "settings_ip": "כתובת ה-IP של ה-WSA", 54 | "settings_autostart": "הפעל אוטומטית את WSA לפני ההתקנה", 55 | "settings_timeout": "זמן מינימלי ({seconds} שניות)", 56 | "settings_language": "שפה", 57 | "settings_option_generic_system": "מערכת", 58 | "settings_option_generic_disabled": "כבוי", 59 | 60 | 61 | "theme_mode": "ערכת נושא", 62 | "theme_mode_dark": "כהה", 63 | "theme_mode_light": "בהיר", 64 | "theme_mica": "שקיפות חלון", 65 | "theme_mica_full": "מלא", 66 | "theme_mica_partial": "חלקי", 67 | "theme_icon_adaptive": "צורת אייקונים מותאמת", 68 | "theme_icon_adaptive_squircle": "Squircle (צורה בין ריבוע לעיגול)", 69 | "theme_icon_adaptive_circle": "עגול", 70 | "theme_icon_adaptive_rounded_square": "ריבוע עם פינות מעוגלות", 71 | 72 | 73 | "installer_message": "האם ברצונך להתקין את היישום הזה?", 74 | "installer_info_version": "גרסה: {appVersion}", 75 | "installer_info_version_change": "גרסה ישנה: {appVersionOld} גרסה חדשה: {appVersionNew}", 76 | "installer_info_package": "חתימה: {appPackage}", 77 | "installer_installing": "מתקין את האפליקציה {appTitle}...", 78 | "installer_installed": "האפליקציה {appTitle} הותקנה בהצלחה", 79 | "installer_fail": "האפליקציה {appTitle} לא הותקנה", 80 | "installer_error_nomsg": "ההתקנה נכשלה, אבל לא זוהתה השגיאה.", 81 | "installer_error_timeout": "התקנה עברה את הזמן המוקצב, הלקוח לא מחכה עוד, אבל היא עדיין עשויה להיערך ברקע...", 82 | "installer_warning_dirty": "נדרשת ניקוי ידני של קבצים בספרייה “{tempDir}”", 83 | "installer_btn_starting": "WSA מפעיל את...", 84 | "installer_btn_loading": "טוען...", 85 | "installer_btn_cancel": "ביטול", 86 | "installer_btn_install": "התקן", 87 | "installer_btn_reinstall": "התקן מחדש", 88 | "installer_btn_update": "עדכון", 89 | "installer_btn_downgrade": "שדרוג גרסה לאחור (לא בטוח)", 90 | "installer_btn_dismiss": "סגור", 91 | "installer_btn_open": "פתח אפליקציה", 92 | "installer_btn_checkbox_shortcut": "צור קיצור דרך בשולחן העבודה", 93 | 94 | 95 | "android_permission_none": "אין צורך בהרשאות", 96 | "android_permission_admin": "נהל את המכשיר כמנהל", 97 | "android_permission_admin_brick": "השבת או אפס את המכשיר מרחוק", 98 | "android_permission_admin_lock": "נעל את המכשיר מרחוק", 99 | "android_permission_storage": "קבצים ומדיה", 100 | "android_permission_microphone": "מיקרופון", 101 | "android_permission_camera": "מצלמה", 102 | "android_permission_location": "מיקום", 103 | "android_permission_phone": "טלפון", 104 | "android_permission_call_log": "יומן שיחות", 105 | "android_permission_sms": "הודעות", 106 | "android_permission_contacts": "אנשי קשר", 107 | "android_permission_calendar": "לוח שנה", 108 | "android_permission_activity_recognition": "פעילות גופנית", 109 | "android_permission_sensors": "חיישני מכשיר", 110 | "android_permission_sensors_body": "חיישני גוף", 111 | "android_permission_nearby_devices": "אתר מכשירים קרובים" 112 | } 113 | -------------------------------------------------------------------------------- /locale/it.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@locale": "it", 3 | "@locale_desc": {"description": "Italian (Italia) [it_IT]"}, 4 | "locale_desc": "Italiano", 5 | "locale_system": "Sistema", 6 | 7 | 8 | "btn_boot": "Avvia", 9 | "btn_auth": "Riautentica", 10 | "btn_dev_settings": "Opzioni sviluppatore", 11 | "btn_switch_on": "On", 12 | "btn_switch_off": "Off", 13 | 14 | 15 | "status_subtext_winver_10": "rilevato Windows 10", 16 | "status_subtext_winver_older": "rilevata una vecchia versione di Windows", 17 | 18 | 19 | "status_unsupported": "WSA non installato", 20 | "status_unsupported_desc": "WSA non trovato e {windowsVersion}; l'applicazione necessita WSA, che è ufficialmente supportato soltanto su Windows 11", 21 | "status_unauthorized": "Non autorizzato", 22 | "status_unauthorized_desc": "L'autorizzazione per il debug è stata negata o revocata; premere il primo pulsante, selezionare 'consenti sempre' e quindi fare clic su 'consenti'; Se non compare alcuna finestra pop-up, aprire le opzioni sviluppatore e disattivare e riattivare l'opzione 'Debug USB'", 23 | "status_missing": "WSA non installato", 24 | "status_missing_desc": "WSA non trovato; l'applicazione necessita WSA, per favore installa il Sottosistema Windows per Android (o l'Amazon Appstore) dallo Store di Microsoft", 25 | "status_unknown": "Connessione", 26 | "status_unknown_desc": "In attesa di una connessione con WSA...", 27 | "status_starting": "Avvio", 28 | "status_starting_desc": "WSA è in fase di avvio, per favore attendi...", 29 | "status_arrested": "Arrestato", 30 | "status_arrested_desc": "WSA è spento", 31 | "status_offline": "Offline", 32 | "status_offline_desc": "Non è stato possibile connettersi a WSA: controlla che la modalità sviluppatore e il debug USB siano attivi, e di aver specificato la porta corretta", 33 | "status_disconnected": "Disconnesso", 34 | "status_disconnected_desc": "Non è stato possibile connettersi a WSA per ragioni sconosciute", 35 | "status_connected": "Connesso", 36 | "status_connected_desc": "Connesso correttamente a WSA, applicazione pronta", 37 | 38 | 39 | "screen_wsa": "WSA Package Manager", 40 | "screen_settings": "Impostazioni", 41 | 42 | 43 | "wsa_manage": "Gestione Android", 44 | "wsa_manage_app": "Gestione Applicazioni", 45 | "wsa_manage_settings": "Gestione Impostazioni", 46 | 47 | 48 | "settings_port": "Porta WSA", 49 | "settings_ip": "Indirizzo IP WSA", 50 | "settings_autostart": "Avvia WSA automaticamente prima di un'installazione", 51 | "settings_timeout": "Timeout ({seconds} secondi)", 52 | "settings_language": "Lingua", 53 | "settings_option_generic_system": "Sistema", 54 | "settings_option_generic_disabled": "Disabilitato", 55 | 56 | 57 | "theme_mode": "Modalità tema", 58 | "theme_mode_dark": "Scuro", 59 | "theme_mode_light": "Chiaro", 60 | "theme_mica": "Trasparenza finestra", 61 | "theme_mica_full": "Completa", 62 | "theme_mica_partial": "Parziale", 63 | "theme_icon_adaptive": "Forma icone adattive", 64 | "theme_icon_adaptive_squircle": "Supercerchio", 65 | "theme_icon_adaptive_circle": "Cerchio", 66 | "theme_icon_adaptive_rounded_square": "Quadrato arrotondato", 67 | 68 | 69 | "installer_message": "Vuoi installare questa applicazione?", 70 | "installer_info_version": "Versione: {appVersion}", 71 | "installer_info_version_change": "Versione: {appVersionOld} => {appVersionNew}", 72 | "installer_info_package": "Pacchetto: {appPackage}", 73 | "installer_installing": "Installazione di {appTitle} in corso...", 74 | "installer_installed": "Applicazione {appTitle} installata correttamente", 75 | "installer_fail": "L'applicazione {appTitle} non è stata installata", 76 | "installer_error_nomsg": "Installazione fallita senza lanciare alcun errore", 77 | "installer_error_timeout": "L'installazione ha superato il tempo limite, il client ha smesso di attendere, ma potrebbe essere ancora in esecuzione in background...", 78 | "installer_warning_dirty": "È necessaria una pulizia manuale dei file della directory “{tempDir}”", 79 | "installer_btn_starting": "Avvio...", 80 | "installer_btn_loading": "Caricamento...", 81 | "installer_btn_cancel": "Annulla", 82 | "installer_btn_install": "Installa", 83 | "installer_btn_reinstall": "Reinstalla", 84 | "installer_btn_update": "Aggiorna", 85 | "installer_btn_downgrade": "Downgrade (non sicuro)", 86 | "installer_btn_dismiss": "Termina", 87 | "installer_btn_open": "Apri l'app", 88 | "installer_btn_checkbox_shortcut": "Aggiungi icona sul desktop", 89 | 90 | 91 | "android_permission_none": "Nessun permesso necessario", 92 | "android_permission_admin": "Gestisci dispositivo come amministratore", 93 | "android_permission_admin_brick": "Disabilita o ripristina dispositivo a distanza", 94 | "android_permission_admin_lock": "Blocca dispositivo a distanza", 95 | "android_permission_storage": "File e contenuti multimediali", 96 | "android_permission_microphone": "Microfono", 97 | "android_permission_camera": "Camera", 98 | "android_permission_location": "Posizione", 99 | "android_permission_phone": "Telefono", 100 | "android_permission_call_log": "Registri chiamate", 101 | "android_permission_sms": "Messaggi", 102 | "android_permission_contacts": "Contatti", 103 | "android_permission_calendar": "Calendario", 104 | "android_permission_activity_recognition": "Attività fisica", 105 | "android_permission_sensors": "Sensori del dispositivo", 106 | "android_permission_sensors_body": "Sensori corporei", 107 | "android_permission_nearby_devices": "Localizza dispositivi vicini" 108 | } -------------------------------------------------------------------------------- /locale/ja.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@locale": "ja", 3 | "@locale_desc": {"description": "Japanese [ja_JP]"}, 4 | "locale_desc": "日本語", 5 | "@locale_system": {"description": "システム ロケールを記述します"}, 6 | "locale_system": "システム", 7 | 8 | 9 | "btn_boot": "オンにする", 10 | "btn_auth": "再認証", 11 | "btn_dev_settings": "開発者オプション", 12 | "btn_switch_on": "オン", 13 | "btn_switch_off": "オフ", 14 | 15 | 16 | "status_subtext_winver_10": "Windows 10", 17 | "status_subtext_winver_older": "古い Windows のバージョン", 18 | 19 | 20 | "status_unsupported": "WSA がインストールされていません。", 21 | "status_unsupported_desc": "{windowsVersion} を使用しています。Windows にWSA がインストールされていません。このアプリケーションを使用するには WSA が必要で、Windows 11 のみ正式にサポートされています。", 22 | "status_unauthorized": "未認証", 23 | "status_unauthorized_desc": "デバッグ認証は拒否されたか、取り消されました。最初のボタンを押し、「常に許可」を選択し、「許可」をクリックしてください。ポップアップが表示されない場合は、開発者オプションを開き、「USBデバッグ」を無効にして再度有効にしてください。", 24 | "status_missing": "WSA がインストールされていません。", 25 | "status_missing_desc": "WSA が見つかりません。このアプリケーションを使用するにはWSAが必要です。Microsoft StoreからAndroid™️ 用 Windows サブシステムをインストールしてください。", 26 | "status_unknown": "接続中", 27 | "status_unknown_desc": "WSA との接続が確立されるのを待っています...", 28 | "status_starting": "起動中", 29 | "status_starting_desc": "WSA が起動しています。しばらくお待ちください...", 30 | "status_arrested": "停止中", 31 | "status_arrested_desc": "WSA が停止しています。", 32 | "status_offline": "オフライン", 33 | "status_offline_desc": "WSA との接続を確立できませんでした: 開発者モードや USB デバッグが無効になっているか、間違ったポートが指定されている可能性があります。", 34 | "status_disconnected": "切断", 35 | "status_disconnected_desc": "WSA との接続が不明な理由で確立できませんでした。", 36 | "status_connected": "接続完了", 37 | "status_connected_desc": "WSA との接続ができました。現在、待機中です。", 38 | 39 | 40 | "screen_wsa": "WSA Package Manager", 41 | "screen_settings": "設定", 42 | 43 | 44 | "wsa_manage": "Android の管理", 45 | "wsa_manage_app": "WSA のアプリケーション設定を開く", 46 | "wsa_manage_settings": "WSA の設定を開く", 47 | 48 | 49 | "settings_port": "WSA ポート", 50 | "settings_ip": "WSA IP アドレス", 51 | "settings_autostart": "インストール前に WSA を自動起動する", 52 | "settings_timeout": "タイムアウト ({seconds} 秒)", 53 | "settings_language": "言語", 54 | "settings_option_generic_system": "システム", 55 | "settings_option_generic_disabled": "非アクティブ", 56 | 57 | 58 | "theme_mode": "テーマモード", 59 | "theme_mode_dark": "ダーク", 60 | "theme_mode_light": "ライト", 61 | "theme_mica": "ウィンドウの透明度", 62 | "theme_mica_full": "全体", 63 | "theme_mica_partial": "一部", 64 | "theme_icon_adaptive": "アダプティブアイコンのスタイル", 65 | "theme_icon_adaptive_squircle": "半円", 66 | "theme_icon_adaptive_circle": "円", 67 | "theme_icon_adaptive_rounded_square": "丸み正方形", 68 | 69 | 70 | "installer_message": "このアプリケーションをインストールしますか?", 71 | "installer_info_version": "バージョン: {appVersion}", 72 | "installer_info_version_change": "バージョン: {appVersionOld} ⇒ {appVersionNew}", 73 | "installer_info_package": "パッケージ: {appPackage}", 74 | "installer_installing": "アプリ「{appTitle}」をインストールしています...", 75 | "installer_installed": "アプリ「{appTitle}」がインストールされました。", 76 | "installer_fail": "アプリ「{appTitle}」をインストールできませんでした。", 77 | "installer_error_nomsg": "インストールに失敗しました。", 78 | "installer_error_timeout": "インストールがタイムアウトしました。クライアントはもう待っていませんが、バックグラウンドではまだ実行されている可能性があります...", 79 | "installer_warning_dirty": "「{tempDir}」ディレクトリでの手動ファイルクリーンアップが必要です", 80 | "installer_btn_starting": "起動中です...", 81 | "installer_btn_loading": "読み込んでいます...", 82 | "installer_btn_cancel": "キャンセル", 83 | "installer_btn_install": "インストール", 84 | "installer_btn_reinstall": "再インストール", 85 | "installer_btn_update": "アップデート", 86 | "installer_btn_downgrade": "ダウングレード(非推奨)", 87 | "installer_btn_dismiss": "閉じる", 88 | "installer_btn_open": "アプリを開く", 89 | "installer_btn_checkbox_shortcut": "デスクトップにショートカットを作成する", 90 | 91 | 92 | "android_permission_none": "権限は必要ありません", 93 | "android_permission_admin": "管理者としてデバイスを管理", 94 | "android_permission_admin_brick": "デバイスをリモートで無効にする", 95 | "android_permission_admin_lock": "デバイスをリモートでロックする", 96 | "android_permission_storage": "ファイルとメディア", 97 | "android_permission_microphone": "マイク", 98 | "android_permission_camera": "カメラ", 99 | "android_permission_location": "位置情報", 100 | "android_permission_phone": "電話", 101 | "android_permission_call_log": "通話ログ", 102 | "android_permission_sms": "メッセージ", 103 | "android_permission_contacts": "連絡先", 104 | "android_permission_calendar": "カレンダー", 105 | "android_permission_activity_recognition": "身体活動", 106 | "android_permission_sensors": "デバイスセンサー", 107 | "android_permission_sensors_body": "ボディセンサー", 108 | "android_permission_nearby_devices": "近くのデバイスを探す" 109 | } 110 | -------------------------------------------------------------------------------- /locale/ko.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@README_1": "The en.arb file is a template for other files", 3 | "@@README_2": "For other languages, entries starting with @ and @@ are not needed, except @@locale", 4 | "@@README_3": "Country-specific locales (eg. 'en_GB') need a fallback locale (eg. 'en') to exist", 5 | 6 | 7 | "@@locale": "ko", 8 | "@locale_desc": {"description": "Korean [ko_KR]"}, 9 | "locale_desc": "한국어", 10 | "@locale_system": {"description": "시스템 언어를 지칭합니다"}, 11 | "locale_system": "시스템", 12 | 13 | 14 | "btn_boot": "켜기", 15 | "btn_auth": "다시 인증", 16 | "btn_dev_settings": "개발자 옵션", 17 | "btn_switch_on": "켬", 18 | "btn_switch_off": "끔", 19 | 20 | 21 | "status_subtext_winver_10": "Windows 10", 22 | "status_subtext_winver_older": "구형 Windows", 23 | 24 | 25 | "status_unsupported": "WSA가 설치되지 않음", 26 | "status_unsupported_desc": "운영 체제가 {windowsVersion}인 것으로 보이며 WSA를 찾을 수 없습니다. 본 프로그램은 WSA에 종속되어 있으며, Windows 11에서만 이용할 수 있습니다.", 27 | "status_unauthorized": "인증되지 않음", 28 | "status_unauthorized_desc": "디버깅 인증이 거부되었거나 취소되었습니다. 첫 번째 버튼을 누르고 '항상 허용'을 선택하고 '허용'을 클릭하세요. 팝업이 나타나지 않으면 개발자 옵션을 열고 USB 디버깅을 비활성화하고 재활성화하세요.", 29 | "status_missing": "WSA가 설치되지 않음", 30 | "status_missing_desc": "WSA를 찾을 수 없습니다. 본 프로그램은 WSA에 종속되어 있으므로, Microsoft Store에서 Windows Subsystem for Android (또는 Amazon 앱스토어)를 설치하십시오.", 31 | "status_unknown": "연결 중", 32 | "status_unknown_desc": "WSA에 연결되기를 기다리고 있습니다...", 33 | "status_starting": "시작 중", 34 | "status_starting_desc": "WSA를 시작하고 있습니다, 잠시 기다려주십시오...", 35 | "status_arrested": "정지됨", 36 | "status_arrested_desc": "WSA가 꺼졌습니다", 37 | "status_offline": "오프라인", 38 | "status_offline_desc": "WSA에 연결할 수 없습니다: 개발자 모드 및 USB 디버깅이 꺼져 있거나 포트가 잘못 지정되었습니다", 39 | "status_disconnected": "연결 끊김", 40 | "status_disconnected_desc": "알 수 없는 이유로 WSA에 연결할 수 없습니다", 41 | "status_connected": "연결됨", 42 | "status_connected_desc": "WSA에 성공적으로 연결했으며, 모든 시스템이 구동되고 있습니다", 43 | 44 | 45 | "screen_wsa": "WSA 패키지 관리자", 46 | "screen_settings": "설정", 47 | 48 | 49 | "wsa_manage": "Android 관리", 50 | "wsa_manage_app": "애플리케이션 관리", 51 | "wsa_manage_settings": "설정 관리", 52 | 53 | 54 | "settings_port": "WSA 포트", 55 | "settings_ip": "WSA IP 주소", 56 | "settings_autostart": "설치 전 WSA 자동 실행", 57 | "settings_timeout": "시간 초과 ({seconds} 초)", 58 | "settings_language": "언어", 59 | "settings_option_generic_system": "시스템", 60 | "settings_option_generic_disabled": "꺼짐", 61 | 62 | 63 | "theme_mode": "테마", 64 | "theme_mode_dark": "어둡게", 65 | "theme_mode_light": "밝게", 66 | "theme_mica": "투명 창", 67 | "theme_mica_full": "전체", 68 | "theme_mica_partial": "일부", 69 | "theme_icon_adaptive": "적응형 아이콘 모양", 70 | "theme_icon_adaptive_squircle": "스퀘어클", 71 | "theme_icon_adaptive_circle": "원형", 72 | "theme_icon_adaptive_rounded_square": "모서리가 둥근 사각형", 73 | 74 | 75 | "installer_message": "이 애플리케이션을 설치하시겠습니까?", 76 | "installer_info_version": "버전: {appVersion}", 77 | "installer_info_version_change": "버전: {appVersionOld} => {appVersionNew}", 78 | "installer_info_package": "패키지: {appPackage}", 79 | "installer_installing": "{appTitle} 앱을 설치하고 있습니다...", 80 | "installer_installed": "{appTitle} 앱이 성공적으로 설치되었습니다", 81 | "installer_fail": "{appTitle} 앱이 설치되지 않았습니다", 82 | "installer_error_nomsg": "설치에 실패하였으나, 오류를 확인할 수 없습니다", 83 | "installer_error_timeout": "설치가 시간 초과되었습니다. 클라이언트는 더 이상 기다리지 않지만 백그라운드에서는 아직 진행 중일 수 있습니다...", 84 | "installer_warning_dirty": "디렉터리 “{tempDir}” 에서 수동 파일 정리가 필요합니다", 85 | "installer_btn_starting": "시작하는 중...", 86 | "installer_btn_loading": "불러오는 중...", 87 | "installer_btn_cancel": "취소", 88 | "installer_btn_install": "설치", 89 | "installer_btn_reinstall": "재설치", 90 | "installer_btn_update": "업데이트", 91 | "installer_btn_downgrade": "다운그레이드 (불안정)", 92 | "installer_btn_dismiss": "다시는 알리지 않음", 93 | "installer_btn_open": "앱 열기", 94 | "installer_btn_checkbox_shortcut": "바탕화면 바로가기 생성", 95 | 96 | 97 | "android_permission_none": "권한 필요 없음", 98 | "android_permission_admin": "관리자 권한으로 기기 관리", 99 | "android_permission_admin_brick": "기기 원격 비활성화 및 초기화", 100 | "android_permission_admin_lock": "기기 원격 잠금", 101 | "android_permission_storage": "파일 및 미디어", 102 | "android_permission_microphone": "마이크", 103 | "android_permission_camera": "카메라", 104 | "android_permission_location": "위치", 105 | "android_permission_phone": "전화", 106 | "android_permission_call_log": "통화 기록", 107 | "android_permission_sms": "메시지", 108 | "android_permission_contacts": "주소록", 109 | "android_permission_calendar": "일정", 110 | "android_permission_activity_recognition": "신체 활동", 111 | "android_permission_sensors": "기기 센서", 112 | "android_permission_sensors_body": "신체 센서", 113 | "android_permission_nearby_devices": "근처 장치 찾기" 114 | } 115 | -------------------------------------------------------------------------------- /locale/pl.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@locale": "pl", 3 | "@locale_desc": {"description": "Polish (PL) [pl_PL]"}, 4 | "locale_desc": "Polski", 5 | "locale_system": "Systemowy", 6 | 7 | 8 | "btn_boot": "Włącz", 9 | "btn_auth": "Ponownie uwierzytelnij", 10 | "btn_dev_settings": "Opcje dla programistów", 11 | "btn_switch_on": "Wł.", 12 | "btn_switch_off": "Wył.", 13 | 14 | 15 | "status_subtext_winver_10": "Windows 10", 16 | "status_subtext_winver_older": "Starsza wersja systemu Windows", 17 | 18 | 19 | "status_unsupported": "WSA nie jest zainstalowany", 20 | "status_unsupported_desc": "Wykryto {windowsVersion} i nie znaleziono WSA; ta aplikacja jest zależna od WSA, który jest oficjalnie wspierany tylko w systemie Windows 11", 21 | "status_unauthorized": "Nieupoważniony", 22 | "status_unauthorized_desc": "Autoryzacja debugowania została odrzucona lub cofnięta; naciśnij pierwszy przycisk, wybierz 'zawsze zezwalaj' i kliknij 'zezwól'; jeśli nie pojawi się okno dialogowe, otwórz opcje dla programistów i wyłącz i włącz ponownie 'debugowanie USB'", 23 | "status_missing": "WSA nie jest zainstalowany", 24 | "status_missing_desc": "Nie znaleziono WSA; ta aplikacja jest zależna od WSA, zainstaluj Podsystem Windows dla systemu Android (lub Amazon Appstore) ze sklepu Microsoft Store", 25 | "status_unknown": "Łączenie", 26 | "status_unknown_desc": "Oczekiwanie na nawiązanie połączenia z WSA...", 27 | "status_starting": "Uruchamianie", 28 | "status_starting_desc": "WSA uruchamia się, proszę czekać...", 29 | "status_arrested": "Zatrzymany", 30 | "status_arrested_desc": "WSA jest wyłączony", 31 | "status_offline": "Offline", 32 | "status_offline_desc": "Nie można nawiązać połączenia z WSA: tryb programisty i debugowanie USB są wyłączone lub podano niewłaściwy port", 33 | "status_disconnected": "Odłączony", 34 | "status_disconnected_desc": "Z nieznanych przyczyn nie udało się nawiązać połączenia z WSA", 35 | "status_connected": "Połączony", 36 | "status_connected_desc": "Pomyślnie połączono z WSA, wszystkie systemy działają", 37 | 38 | 39 | "screen_wsa": "Menedżer pakietów WSA", 40 | "screen_settings": "Ustawienia", 41 | 42 | 43 | "wsa_manage": "Zarządzanie Androidem", 44 | "wsa_manage_app": "Aplikacje", 45 | "wsa_manage_settings": "Ustawienia", 46 | 47 | 48 | "settings_port": "Port WSA", 49 | "settings_ip": "Adres IP WSA", 50 | "settings_autostart": "Autostart WSA przed instalacją", 51 | "settings_timeout": "Limit czasowy ({seconds} sekund)", 52 | "settings_language": "Język", 53 | "settings_option_generic_system": "Systemowy", 54 | "settings_option_generic_disabled": "Wyłączone", 55 | 56 | 57 | "theme_mode": "Motyw", 58 | "theme_mode_dark": "Ciemny", 59 | "theme_mode_light": "Jasny", 60 | "theme_mica": "Przezroczystość okna", 61 | "theme_mica_full": "Pełna", 62 | "theme_mica_partial": "Częściowa", 63 | "theme_icon_adaptive": "Adaptacyjny kształt ikon", 64 | "theme_icon_adaptive_squircle": "Domyślny", 65 | "theme_icon_adaptive_circle": "Okrągły", 66 | "theme_icon_adaptive_rounded_square": "Zaokrąglony kwadrat", 67 | 68 | 69 | "installer_message": "Czy chcesz zainstalować tą aplikację?", 70 | "installer_info_version": "Wersja: {appVersion}", 71 | "installer_info_version_change": "Wersja: {appVersionOld} => {appVersionNew}", 72 | "installer_info_package": "Pakiet: {appPackage}", 73 | "installer_installing": "Instalowanie aplikacji {appTitle}...", 74 | "installer_installed": "Aplikacja {appTitle} została pomyślnie zainstalowana", 75 | "installer_fail": "Aplikacja {appTitle} nie została zainstalowana", 76 | "installer_error_nomsg": "Instalacja nie powiodła się, ale nie zgłoszono żadnego błędu", 77 | "installer_error_timeout": "Instalacja przekroczyła czas oczekiwania, klient przestał czekać, ale może nadal trwać w tle...", 78 | "installer_warning_dirty": "Wymagane jest ręczne czyszczenie plików w katalogu „{tempDir}”", 79 | "installer_btn_starting": "Rozpoczynanie...", 80 | "installer_btn_loading": "Wczytywanie...", 81 | "installer_btn_cancel": "Anuluj", 82 | "installer_btn_install": "Zainstaluj", 83 | "installer_btn_reinstall": "Zainstaluj ponownie", 84 | "installer_btn_update": "Aktualizuj", 85 | "installer_btn_downgrade": "Downgrade (niebezpieczny)", 86 | "installer_btn_dismiss": "Gotowe", 87 | "installer_btn_open": "Otwórz", 88 | "installer_btn_checkbox_shortcut": "Utwórz skrót na pulpicie", 89 | 90 | 91 | "android_permission_none": "Nie wymaga żadnych uprawnień", 92 | "android_permission_admin": "Zarządzanie urządzeniem jako administrator", 93 | "android_permission_admin_brick": "Zdalne wyłączenie lub reset urządzenia", 94 | "android_permission_admin_lock": "Zdalne zablokowanie urządzenia", 95 | "android_permission_storage": "Pliki i multimedia", 96 | "android_permission_microphone": "Mikrofon", 97 | "android_permission_camera": "Aparat", 98 | "android_permission_location": "Lokalizacja", 99 | "android_permission_phone": "Telefon", 100 | "android_permission_call_log": "Rejestry połączeń", 101 | "android_permission_sms": "Wiadomości", 102 | "android_permission_contacts": "Kontakty", 103 | "android_permission_calendar": "Kalendarz", 104 | "android_permission_activity_recognition": "Aktywność fizyczna", 105 | "android_permission_sensors": "Czujniki urządzenia", 106 | "android_permission_sensors_body": "Czujniki na ciele", 107 | "android_permission_nearby_devices": "Wykrywanie urządzeń w pobliżu" 108 | } 109 | -------------------------------------------------------------------------------- /locale/pt.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@locale": "pt", 3 | "@locale_desc": {"description": "Portuguese (Brasil) [pt_BR]"}, 4 | "locale_desc": "Português (Brasil)", 5 | "locale_system": "Sistema", 6 | 7 | 8 | "btn_boot": "Ativar", 9 | "btn_auth": "Reautenticar", 10 | "btn_dev_settings": "Opções de desenvolvedor", 11 | "btn_switch_on": "Lig", 12 | "btn_switch_off": "Desl", 13 | 14 | 15 | "status_subtext_winver_10": "Windows 10", 16 | "status_subtext_winver_older": "Versão antiga do Windows", 17 | 18 | 19 | "status_unsupported": "WSA não instalado", 20 | "status_unsupported_desc": "{windowsVersion} detectado e WSA não encontrado. Este aplicativo depende do WSA, que é suportado oficialmente no Windows 11", 21 | "status_unauthorized": "Não autorizado", 22 | "status_unauthorized_desc": "A autorização de depuração foi negada ou revogada; pressione o primeiro botão, selecione 'permitir sempre' e clique em 'permitir'; se nenhuma janela pop-up aparecer, abra as opções de desenvolvedor e desabilite e reabilite o 'depuração USB'", 23 | "status_missing": "WSA não instalado", 24 | "status_missing_desc": "WSA não encontrado. Este aplicativo depende do WSA, instale o Windows Subsystem for Android (ou Amazon Appstore) da Microsoft Store", 25 | "status_unknown": "Conectando", 26 | "status_unknown_desc": "Aguardando que uma conexão WSA seja estabelecida...", 27 | "status_starting": "Iniciando", 28 | "status_starting_desc": "WSA iniciando, aguarde...", 29 | "status_arrested": "Suspenso", 30 | "status_arrested_desc": "WSA está desativado", 31 | "status_offline": "Offline", 32 | "status_offline_desc": "Não foi estabelecer uma conexão com o WSA. O modo de desenvolvedor e a depuração USB estão desabilitados ou uma porta errada foi especificada", 33 | "status_disconnected": "Desconectado", 34 | "status_disconnected_desc": "Uma conexão WSA não pôde ser estabelecido por razões desconhecidas", 35 | "status_connected": "Conectado", 36 | "status_connected_desc": "Conectado com sucesso no WSA, todos os sistemas ativos", 37 | 38 | 39 | "screen_wsa": "Gerenciador de pacotes WSA ", 40 | "screen_settings": "Configurações", 41 | 42 | 43 | "wsa_manage": "Gerenciamento do Android", 44 | "wsa_manage_app": "Gerenciar aplicativos", 45 | "wsa_manage_settings": "Gerenciar configurações", 46 | 47 | 48 | "settings_port": "Porta da WSA", 49 | "settings_ip": "Endereço IP do WSA", 50 | "settings_autostart": "Iniciar WSA antes da instalação", 51 | "settings_timeout": "Tempo limite ({seconds} segundos)", 52 | "settings_language": "Idioma", 53 | "settings_option_generic_system": "Sistema", 54 | "settings_option_generic_disabled": "Desativado", 55 | 56 | 57 | "theme_mode": "Tema", 58 | "theme_mode_dark": "Escuro", 59 | "theme_mode_light": "Claro", 60 | "theme_mica": "Transparência da janela", 61 | "theme_mica_full": "Cheia", 62 | "theme_mica_partial": "Parcial", 63 | "theme_icon_adaptive": "Forma de ícones adaptáveis", 64 | "theme_icon_adaptive_squircle": "Quadrado-círculo", 65 | "theme_icon_adaptive_circle": "Círculo", 66 | "theme_icon_adaptive_rounded_square": "Quadrado arredondado", 67 | 68 | 69 | "installer_message": "Deseja instalar este aplicativo?", 70 | "installer_info_version": "Versão: {appVersion}", 71 | "installer_info_version_change": "Versão: {appVersionOld} => {appVersionNew}", 72 | "installer_info_package": "Pacote: {appPackage}", 73 | "installer_installing": "Instalando aplicativo {appTitle}...", 74 | "installer_installed": "O aplicativo {appTitle} foi instalado com sucesso", 75 | "installer_fail": "O aplicativo {appTitle} não foi instalado", 76 | "installer_error_nomsg": "A instalação falhou, mas nenhum erro foi emitido", 77 | "installer_error_timeout": "A instalação excedeu o tempo limite, o cliente parou de esperar, mas pode ainda estar em progresso em segundo plano...", 78 | "installer_warning_dirty": "É necessário uma limpeza manual de arquivos no diretório “{tempDir}”", 79 | "installer_btn_starting": "Iniciando...", 80 | "installer_btn_loading": "Carregando...", 81 | "installer_btn_cancel": "Cancelar", 82 | "installer_btn_install": "Instalar", 83 | "installer_btn_reinstall": "Reinstalar", 84 | "installer_btn_update": "Atualizar", 85 | "installer_btn_downgrade": "Downgrade (não seguro)", 86 | "installer_btn_dismiss": "Dispensar", 87 | "installer_btn_open": "Abrir aplicativo", 88 | "installer_btn_checkbox_shortcut": "Criar ícone na Área de Trabalho", 89 | 90 | 91 | "android_permission_none": "Nenhuma permissão necessária", 92 | "android_permission_admin": "Gerenciar dispositivo como administrador", 93 | "android_permission_admin_brick": "Desativar ou redefinir dispositivo remotamente", 94 | "android_permission_admin_lock": "Bloquear dispositivo remotamente", 95 | "android_permission_storage": "Arquivos e mídia", 96 | "android_permission_microphone": "Microfone", 97 | "android_permission_camera": "Câmera", 98 | "android_permission_location": "Local", 99 | "android_permission_phone": "Telefone", 100 | "android_permission_call_log": "Registro de chamadas", 101 | "android_permission_sms": "Mensagens", 102 | "android_permission_contacts": "Contatos", 103 | "android_permission_calendar": "Calendário", 104 | "android_permission_activity_recognition": "Atividade física", 105 | "android_permission_sensors": "Sensores do dispositivo", 106 | "android_permission_sensors_body": "Sensores corporais", 107 | "android_permission_nearby_devices": "Localizar dispositivos próximos" 108 | } 109 | -------------------------------------------------------------------------------- /locale/vi.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@locale": "vi", 3 | "@locale_desc": {"description": "Vietnamese [vi_VN]"}, 4 | "locale_desc": "Tiếng Việt", 5 | "locale_system": "Hệ thống", 6 | 7 | 8 | "btn_boot": "Chế độ", 9 | "btn_auth": "Đăng nhập lại", 10 | "btn_dev_settings": "Tùy chọn nhà phát triển", 11 | "btn_switch_on": "Bật", 12 | "btn_switch_off": "Tắt", 13 | 14 | 15 | "status_subtext_winver_10": "Windows 10", 16 | "status_subtext_winver_older": "Phiên bản Windows cũ hơn", 17 | 18 | 19 | "status_unsupported": "WSA chưa được cài đặt", 20 | "status_unsupported_desc": "{windowsVersion} phát hiện và không tìm thấy WSA; ứng dụng này phụ thuộc vào WSA, chỉ được hỗ trợ chính thức trên Windows 11", 21 | "status_unauthorized": "Không được phép", 22 | "status_unauthorized_desc": "Đã từ chối hoặc thu hồi quyền xác minh gỡ lỗi; nhấn vào nút đầu tiên, chọn 'luôn cho phép', sau đó nhấp vào 'cho phép'; Nếu không có cửa sổ xuất hiện, mở tùy chọn nhà phát triển và vô hiệu hóa rồi bật lại 'gỡ lỗi USB'", 23 | "status_missing": "WSA chưa được cài đặt", 24 | "status_missing_desc": "Không tìm thấy WSA; ứng dụng này phụ thuộc vào WSA, vui lòng cài đặt Windows Subsystem for Android (hoặc Amazon Appstore) từ Microsoft Store", 25 | "status_unknown": "Đang kết nối", 26 | "status_unknown_desc": "Đang đợi kết nối WSA được thiết lập...", 27 | "status_starting": "Bắt đầu", 28 | "status_starting_desc": "WSA đang bắt đầu, vui lòng chờ...", 29 | "status_arrested": "Tắt", 30 | "status_arrested_desc": "WSA đã bị tắt", 31 | "status_offline": "Ngoại tuyến", 32 | "status_offline_desc": "Không thể thiết lập kết nối với WSA: Chế độ nhà phát triển và gỡ lỗi USB đã bị tắt hoặc sai cổng (Port) được chỉ định", 33 | "status_disconnected": "Đã ngắt kết nối", 34 | "status_disconnected_desc": "Kết nối WSA không thể được thiết lập vì những lý do không xác định", 35 | "status_connected": "Đã kết nối", 36 | "status_connected_desc": "Kết nối thành công với WSA, tất cả các hệ thống đều hoạt động", 37 | 38 | 39 | "screen_wsa": "Trình Quản Lý Cài Đặt - WSA", 40 | "screen_settings": "Cài Đặt", 41 | 42 | 43 | "wsa_manage": "Quản Lý Android", 44 | "wsa_manage_app": "Quản lý ứng dụng", 45 | "wsa_manage_settings": "Quản lý cài đặt", 46 | 47 | 48 | "settings_port": "Cổng WSA (Port)", 49 | "settings_ip": "Địa chỉ IP WSA", 50 | "settings_autostart": "Tự động khởi động WSA trước khi cài đặt", 51 | "settings_timeout": "Thời gian chờ ({seconds} giây)", 52 | "settings_language": "Ngôn ngữ", 53 | "settings_option_generic_system": "Hệ thống", 54 | "settings_option_generic_disabled": "Vô hiệu hóa", 55 | 56 | 57 | "theme_mode": "Giao diện", 58 | "theme_mode_dark": "Tối", 59 | "theme_mode_light": "Sáng", 60 | "theme_mica": "Độ trong suốt của cửa sổ", 61 | "theme_mica_full": "Tất cả", 62 | "theme_mica_partial": "Một phần nào đó", 63 | "theme_icon_adaptive": "Biểu tượng icon", 64 | "theme_icon_adaptive_squircle": "Hình vuông", 65 | "theme_icon_adaptive_circle": "Vòng tròn", 66 | "theme_icon_adaptive_rounded_square": "Hình vuông (góc tròn)", 67 | 68 | 69 | "installer_message": "Bạn có muốn cài đặt ứng dụng này không?", 70 | "installer_info_version": "Phiên bản: {appVersion}", 71 | "installer_info_version_change": "Phiên bản: {appVersionOld} => {appVersionNew}", 72 | "installer_info_package": "Gói: {appPackage}", 73 | "installer_installing": "Cài đặt ứng dụng {appTitle}...", 74 | "installer_installed": "Ứng dụng {appTitle} đã được cài đặt thành công", 75 | "installer_fail": "Ứng dụng {appTitle} chưa được cài đặt", 76 | "installer_error_nomsg": "Cài đặt không thành công, nhưng không có lỗi nào được đưa ra", 77 | "installer_error_timeout": "Quá thời gian cài đặt, khách hàng đã ngừng chờ, nhưng nó có thể vẫn đang tiếp diễn ở nền...", 78 | "installer_warning_dirty": "Cần thực hiện việc dọn dẹp tập tin thủ công trong thư mục “{tempDir}”", 79 | "installer_btn_starting": "Đang bắt đầu...", 80 | "installer_btn_loading": "Đang tải...", 81 | "installer_btn_cancel": "Hủy bỏ", 82 | "installer_btn_install": "Cài đặt", 83 | "installer_btn_reinstall": "Cài đặt lại", 84 | "installer_btn_update": "Cập nhật", 85 | "installer_btn_downgrade": "Hạ cấp (không an toàn)", 86 | "installer_btn_dismiss": "Bỏ qua", 87 | "installer_btn_open": "Chạy ứng dụng", 88 | "installer_btn_checkbox_shortcut": "Tạo lối tắt trên màn hình", 89 | 90 | 91 | "android_permission_none": "Không cần quyền", 92 | "android_permission_admin": "Quản lý thiết bị với tư cách Quản Trị Viên", 93 | "android_permission_admin_brick": "Vô hiệu hóa hoặc đặt lại thiết bị từ xa", 94 | "android_permission_admin_lock": "Khóa thiết bị từ xa", 95 | "android_permission_storage": "Tập tin và phương tiện", 96 | "android_permission_microphone": "Microphone", 97 | "android_permission_camera": "Máy ảnh", 98 | "android_permission_location": "Vị trí", 99 | "android_permission_phone": "Điện thoại", 100 | "android_permission_call_log": "Nhật ký cuộc gọi", 101 | "android_permission_sms": "Tin nhắn", 102 | "android_permission_contacts": "Danh bạn", 103 | "android_permission_calendar": "Lịch", 104 | "android_permission_activity_recognition": "Hoạt động thể chất", 105 | "android_permission_sensors": "Cảm biến thiết bị", 106 | "android_permission_sensors_body": "Cảm biến cơ thể", 107 | "android_permission_nearby_devices": "Xác định vị trí các thiết bị lân cận" 108 | } -------------------------------------------------------------------------------- /locale/zh-Hant.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@README_1": "The en.arb file is a template for other files", 3 | "@@README_2": "For other languages, entries starting with @ and @@ are not needed, except @@locale", 4 | "@@README_3": "Country-specific locales (eg. 'en_GB') need a fallback locale (eg. 'en') to exist", 5 | 6 | 7 | "@@locale": "zh_Hant", 8 | "@locale_desc": {"description": "Chinese (traditional) [zh_TW] < [zh_Hant]"}, 9 | "locale_desc": "中文 (繁體)", 10 | "@locale_system": {"description": "描述系統區域設定"}, 11 | "locale_system": "系統", 12 | 13 | 14 | "btn_boot": "啟動", 15 | "btn_auth": "重新驗證", 16 | "btn_dev_settings": "開發者選項", 17 | "btn_switch_on": "開", 18 | "btn_switch_off": "關", 19 | 20 | 21 | "@status_subtext_winver_10": {"description": "Only used inside 'status_unsupported_desc', modify taking this in consideration"}, 22 | "status_subtext_winver_10": "Windows 10", 23 | "@status_subtext_winver_older": {"description": "Only used inside 'status_unsupported_desc', modify taking this in consideration"}, 24 | "status_subtext_winver_older": "舊 Windows 版本", 25 | 26 | 27 | "status_unsupported": "尚未安裝 WSA ", 28 | "status_unsupported_desc": "檢測到 {windowsVersion} 但未找到 Android 子系統;此應用程式僅在 Windows 11 正式支援。", 29 | "status_unauthorized": "未授權", 30 | "status_unauthorized_desc": "調試授權被拒絕或撤銷;按一下第一個按鈕,選擇“總是允許”,然後點擊“允許”;如果沒有彈出窗口,請打開開發人員選項並禁用和重新啟用“USB調試”", 31 | "status_missing": "未安裝 Android 子系統", 32 | "status_missing_desc": "未找到 Android 子系統;請從 Microsoft Store 安裝適用於 Windows 的 Android 子系統(或 Amazon Appstore)。", 33 | "status_unknown": "正在連接", 34 | "status_unknown_desc": "正在等待建立 WSA 連接...", 35 | "status_starting": "正在啟動", 36 | "status_starting_desc": "WSA 正在啟動,請稍候...", 37 | "status_arrested": "已停滯", 38 | "status_arrested_desc": "WSA 已關閉", 39 | "status_offline": "離線", 40 | "status_offline_desc": "無法與 Android 子系統建立連接:可能的原因是未開啟開發者模式或 USB 調試被關閉或被指定了錯誤的端口。", 41 | "status_disconnected": "已斷開連接", 42 | "status_disconnected_desc": "由於未知原因,無法建立 WSA 連線", 43 | "status_connected": "已連接", 44 | "status_connected_desc": "成功連接到 WSA,所有系統正常執行", 45 | 46 | 47 | "screen_wsa": "WSA 包管理器", 48 | "screen_settings": "設定", 49 | 50 | 51 | "wsa_manage": "Android 管理", 52 | "wsa_manage_app": "管理應用程式", 53 | "wsa_manage_settings": "管理設定", 54 | 55 | 56 | "settings_port": "WSA 端口", 57 | "settings_ip": "WSA 的 IP 位址", 58 | "settings_autostart": "在安裝之前自動啟動 WSA", 59 | "settings_timeout": "逾時 ({seconds} 秒)", 60 | "settings_language": "語言", 61 | "settings_option_generic_system": "系統", 62 | "settings_option_generic_disabled": "已關閉", 63 | 64 | 65 | "theme_mode": "主題模式", 66 | "theme_mode_dark": "深色模式", 67 | "theme_mode_light": "淺色模式", 68 | "theme_mica": "視窗透明度", 69 | "theme_mica_full": "完整", 70 | "theme_mica_partial": "部分", 71 | "theme_icon_adaptive": "自適應圖標形狀", 72 | "theme_icon_adaptive_squircle": "方圓形", 73 | "theme_icon_adaptive_circle": "圓形", 74 | "theme_icon_adaptive_rounded_square": "圓角方形", 75 | 76 | 77 | "installer_message": "您要安裝此應用程式嗎?", 78 | "installer_info_version": "版本:{appVersion}", 79 | "installer_info_version_change": "版本:{appVersionOld} => {appVersionNew}", 80 | "installer_info_package": "包名:{appPackage}", 81 | "installer_installing": "正在安裝 {appTitle} 應用程式...", 82 | "installer_installed": "應用程式 {appTitle} 已成功安裝", 83 | "installer_fail": "應用程式 {appTitle} 未安裝", 84 | "installer_error_nomsg": "安裝失敗,但未拋出錯誤", 85 | "installer_error_timeout": "安裝已超時,客戶端已停止等待,但可能仍在背景執行...", 86 | "installer_warning_dirty": "目錄『{tempDir}』需要手動清理文件", 87 | "installer_btn_starting": "Android 子系統啟動中...", 88 | "installer_btn_loading": "應用程式加載中...", 89 | "installer_btn_cancel": "取消", 90 | "installer_btn_install": "安裝", 91 | "installer_btn_reinstall": "重新安裝", 92 | "installer_btn_update": "更新", 93 | "installer_btn_downgrade": "降級(不安全)", 94 | "installer_btn_dismiss": "完成", 95 | "installer_btn_open": "開啟應用程式", 96 | "installer_btn_checkbox_shortcut": "建立桌面快捷方式", 97 | 98 | 99 | "android_permission_none": "不需要任何權限", 100 | "android_permission_admin": "以管理員身份管理裝置", 101 | "android_permission_admin_brick": "遠程停用或重設裝置", 102 | "android_permission_admin_lock": "遠程鎖定裝置", 103 | "android_permission_storage": "多媒體檔案", 104 | "android_permission_microphone": "麥克風", 105 | "android_permission_camera": "相機", 106 | "android_permission_location": "位置", 107 | "android_permission_phone": "電話", 108 | "android_permission_call_log": "通訊記錄", 109 | "android_permission_sms": "訊息", 110 | "android_permission_contacts": "聯絡人", 111 | "android_permission_calendar": "日曆", 112 | "android_permission_activity_recognition": "體育活動", 113 | "android_permission_sensors": "裝置傳感器", 114 | "android_permission_sensors_body": "身體傳感器", 115 | "android_permission_nearby_devices": "查找附近的裝置" 116 | } 117 | -------------------------------------------------------------------------------- /locale/zh.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@README_1": "en.arb 文件是其他文件的模板", 3 | "@@README_2": "对于其他语言,不需要翻译 @ 和 @@ 开头的条目,除外 @@locale", 4 | "@@README_3": "特定于国家/地区的语言环境(例如“en_GB”)需要一个备用语言环境(例如“en”)才能使用", 5 | 6 | 7 | "@@locale": "zh", 8 | "@locale_desc": {"description": "Chinese (simplified) [zh_CN] < [zh_Hans]"}, 9 | "locale_desc": "中文 (简体)", 10 | "@locale_system": {"description": "描述系统区域设置"}, 11 | "locale_system": "系统", 12 | 13 | 14 | "btn_boot": "启动", 15 | "btn_auth": "重新认证", 16 | "btn_dev_settings": "开发者选项", 17 | "btn_switch_on": "打开", 18 | "btn_switch_off": "关闭", 19 | 20 | 21 | "@status_subtext_winver_10": {"description": "仅在 'status_unsupported_desc' 中使用,修改时考虑到这一点"}, 22 | "status_subtext_winver_10": "Windows 10", 23 | "@status_subtext_winver_older": {"description": "仅在 'status_unsupported_desc' 中使用,修改时考虑到这一点"}, 24 | "status_subtext_winver_older": "旧 Windows 版本", 25 | 26 | 27 | "status_unsupported": "WSA 未安装", 28 | "status_unsupported_desc": "{windowsVersion} 检测到但未找到 WSA; 此应用程序依赖于 WSA,仅在 Windows 11 上正式支持", 29 | "status_unauthorized": "未授权", 30 | "status_unauthorized_desc": "调试授权被拒绝或撤销;点击第一个按钮,选择“始终允许”,然后点击“允许”;如果没有弹出窗口,请打开开发者选项并禁用和重新启用“USB调试”", 31 | "status_missing": "WSA 未安装", 32 | "status_missing_desc": "未找到 WSA; 此应用程序依赖 WSA,请从 Microsoft Store 安装适用于 Android 的 Windows 子系统(或 Amazon Appstore)", 33 | "status_unknown": "正在连接", 34 | "status_unknown_desc": "正在等待建立 WSA 连接...", 35 | "status_starting": "正在启动", 36 | "status_starting_desc": "WSA 正在启动,请稍候...", 37 | "status_arrested": "已停滞", 38 | "status_arrested_desc": "WSA 已关闭", 39 | "status_offline": "离线", 40 | "status_offline_desc": "无法与 WSA 建立连接:开发者模式和 USB 调试被禁用或指定了错误的端口", 41 | "status_disconnected": "已断开连接", 42 | "status_disconnected_desc": "由于未知原因,无法建立 WSA 连接", 43 | "status_connected": "已连接", 44 | "status_connected_desc": "成功连接到 WSA,所有系统正常运行", 45 | 46 | 47 | "screen_wsa": "WSA 包管理器", 48 | "screen_settings": "设置", 49 | 50 | 51 | "wsa_manage": "Android 管理", 52 | "wsa_manage_app": "管理应用程序", 53 | "wsa_manage_settings": "管理设置", 54 | 55 | 56 | "settings_port": "WSA 端口", 57 | "settings_ip": "WSA IP 地址", 58 | "settings_autostart": "在安装之前自动启动 WSA", 59 | "settings_timeout": "超时 ({seconds} 秒)", 60 | "settings_language": "语言", 61 | "settings_option_generic_system": "系统", 62 | "settings_option_generic_disabled": "已禁用", 63 | 64 | 65 | "theme_mode": "主题模式", 66 | "theme_mode_dark": "深色模式", 67 | "theme_mode_light": "浅色模式", 68 | "theme_mica": "窗口透明度", 69 | "theme_mica_full": "完整", 70 | "theme_mica_partial": "部分", 71 | "theme_icon_adaptive": "自适应图标形状", 72 | "theme_icon_adaptive_squircle": "超圆角圆形", 73 | "theme_icon_adaptive_circle": "圆形", 74 | "theme_icon_adaptive_rounded_square": "圆角方形", 75 | 76 | 77 | "installer_message": "您要安装此应用程序吗?", 78 | "installer_info_version": "版本:{appVersion}", 79 | "installer_info_version_change": "版本:{appVersionOld} => {appVersionNew}", 80 | "installer_info_package": "包名:{appPackage}", 81 | "installer_installing": "正在安装 {appTitle} 应用程序...", 82 | "installer_installed": "应用程序 {appTitle} 已成功安装", 83 | "installer_fail": "应用程序 {appTitle} 未安装", 84 | "installer_error_nomsg": "安装失败,但没有抛出错误", 85 | "installer_error_timeout": "安装已超时,客户端已停止等待,但可能仍在后台执行...", 86 | "installer_warning_dirty": "目录「{tempDir}」需要手动清理文件", 87 | "installer_btn_starting": "正在启动...", 88 | "installer_btn_loading": "加载中...", 89 | "installer_btn_cancel": "取消", 90 | "installer_btn_install": "安装", 91 | "installer_btn_reinstall": "重新安装", 92 | "installer_btn_update": "更新", 93 | "installer_btn_downgrade": "降级(不安全)", 94 | "installer_btn_dismiss": "完成", 95 | "installer_btn_open": "打开应用程序", 96 | "installer_btn_checkbox_shortcut": "创建桌面快捷方式", 97 | 98 | 99 | "android_permission_none": "不需要任何权限", 100 | "android_permission_admin": "以管理员身份管理设备", 101 | "android_permission_admin_brick": "远程禁用或重置设备", 102 | "android_permission_admin_lock": "远程锁定设备", 103 | "android_permission_storage": "文件和媒体", 104 | "android_permission_microphone": "麦克风", 105 | "android_permission_camera": "相机", 106 | "android_permission_location": "位置", 107 | "android_permission_phone": "电话", 108 | "android_permission_call_log": "通话记录", 109 | "android_permission_sms": "信息", 110 | "android_permission_contacts": "联系人", 111 | "android_permission_calendar": "日历", 112 | "android_permission_activity_recognition": "体育活动", 113 | "android_permission_sensors": "设备传感器", 114 | "android_permission_sensors_body": "身体传感器", 115 | "android_permission_nearby_devices": "查找附近的设备" 116 | } 117 | -------------------------------------------------------------------------------- /proto/manifest_xapk.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package proto; 4 | option optimize_for = SPEED; 5 | 6 | message ManifestXapk { 7 | // App options 8 | optional uint32 xapk_version = 1 [default = 1]; 9 | optional string package_name = 2; 10 | optional string name = 3; 11 | map locales_name = 4; 12 | optional uint32 version_code = 5; 13 | optional string version_name = 6; 14 | optional uint32 min_sdk_version = 7; 15 | optional uint32 target_sdk_version = 8; 16 | repeated string permissions = 9; 17 | repeated string split_configs = 10; 18 | optional uint32 total_size = 11; 19 | optional string icon = 12; 20 | repeated ApkFile split_apks = 13; 21 | repeated ApkExpansion expansions = 14; 22 | 23 | message ApkFile { 24 | optional string id = 1; 25 | optional string file = 2; 26 | } 27 | 28 | message ApkExpansion { 29 | optional InstallDir install_location = 1; 30 | optional string file = 2; 31 | optional string install_path = 3; 32 | } 33 | 34 | enum InstallDir { 35 | EXTERNAL_STORAGE = 0; 36 | INTERNAL_STORAGE = 1; 37 | } 38 | } -------------------------------------------------------------------------------- /proto/options.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package proto; 4 | option optimize_for = SPEED; 5 | 6 | message Options { 7 | // App options 8 | optional uint32 ipAddress = 1 [default = 2130706433]; 9 | optional uint32 port = 2 [default = 58526]; 10 | optional bool autostart = 8; 11 | optional uint32 timeout = 10 [default = 30]; 12 | // Interface options 13 | optional uint32 locale = 9; 14 | // Theme options 15 | optional Theme theme = 3; 16 | optional bool legacyIcons = 4; 17 | optional bool systemAccent = 5; 18 | optional IconShape iconShape = 6; 19 | optional Mica mica = 7 [default = FULL]; 20 | 21 | enum Theme { 22 | SYSTEM = 0; 23 | LIGHT = 1; 24 | DARK = 2; 25 | } 26 | 27 | enum IconShape { 28 | SQUIRCLE = 0; 29 | CIRCLE = 1; 30 | ROUNDED_SQUARE = 2; 31 | } 32 | 33 | enum Mica { 34 | FULL = 0; 35 | PARTIAL = 1; 36 | DISABLED = 2; 37 | } 38 | } -------------------------------------------------------------------------------- /proto/protoc-generate.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | if not exist "..\lib\proto\" mkdir ..\lib\proto 3 | protoc --dart_out=../lib/proto/ *.proto -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: wsa_pacman 2 | description: A GUI package manager and package installer for Windows Subsystem for Android (WSA). 3 | 4 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 5 | 6 | version: 1.0.0+1 7 | 8 | environment: 9 | sdk: '>=2.17.0 <3.0.0' 10 | flutter: '>=3.0.0 <3.3.10' 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | flutter_localizations: 16 | sdk: flutter 17 | fluent_ui: 3.12.0 18 | #git: https://github.com/bdlukaa/fluent_ui.git 19 | shared_value: ^2.1.2 20 | synchronized: ^3.0.0 21 | provider: ^6.0.0 22 | system_theme: 2.0.0 23 | bitsdojo_window: 24 | git: 25 | # Credits to bufan22 for fixing errors with new Windows versions 26 | url: https://github.com/alesimula/bitsdojo_window.git 27 | path: bitsdojo_window 28 | ref: master 29 | smooth_scroll_multiplatform: 30 | git: https://github.com/alesimula/dyn_mouse_scroll.git 31 | flutter_acrylic: ^1.0.0+2 32 | url_strategy: ^0.2.0 33 | yaml: ^3.1.0 34 | #transparent_pointer: ^1.0.0 35 | archive: #3.1.11 36 | git: https://github.com/brendan-duncan/archive.git 37 | #flutter_svg: ^0.23.0+1 38 | jovial_svg: 39 | git: https://github.com/alesimula/jovial_svg.git 40 | protobuf: ^2.0.0 41 | #path_provider: ^2.0.6 42 | mdi: ^5.0.0-nullsafety.0 43 | win32: ^3.0.0 44 | base32: ^2.1.1 45 | charset: ^0.1.1 46 | 47 | 48 | dev_dependencies: 49 | flutter_test: 50 | sdk: flutter 51 | #flutter_native_splash: ^2.0.1+1 52 | flutter_lints: ^1.0.4 53 | 54 | flutter: 55 | generate: true 56 | uses-material-design: true 57 | assets: 58 | - assets/icons/missing_icon_background.si 59 | - assets/icons/missing_icon_foreground.si 60 | - assets/icons/missing_icon_legacy.si 61 | - assets/images/logo.png 62 | 63 | #flutter_native_splash: 64 | #color: "#42a5f5" 65 | #image: web/assets/flutter_logo.png 66 | 67 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:wsa_pacman/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(wsa_pacman LANGUAGES CXX) 3 | 4 | set(BINARY_NAME "WSA-pacman") 5 | 6 | cmake_policy(SET CMP0063 NEW) 7 | 8 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") 9 | 10 | # Configure build options. 11 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 12 | if(IS_MULTICONFIG) 13 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" 14 | CACHE STRING "" FORCE) 15 | else() 16 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 17 | set(CMAKE_BUILD_TYPE "Debug" CACHE 18 | STRING "Flutter build mode" FORCE) 19 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 20 | "Debug" "Profile" "Release") 21 | endif() 22 | endif() 23 | 24 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") 25 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") 26 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") 27 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") 28 | 29 | # Use Unicode for all projects. 30 | add_definitions(-DUNICODE -D_UNICODE) 31 | 32 | # Compilation settings that should be applied to most targets. 33 | function(APPLY_STANDARD_SETTINGS TARGET) 34 | target_compile_features(${TARGET} PUBLIC cxx_std_17) 35 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") 36 | target_compile_options(${TARGET} PRIVATE /EHsc) 37 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") 38 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") 39 | endfunction() 40 | 41 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 42 | 43 | # Flutter library and tool build rules. 44 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 45 | 46 | # Application build 47 | add_subdirectory("runner") 48 | 49 | # Generated plugin build rules, which manage building the plugins and adding 50 | # them to the application. 51 | include(flutter/generated_plugins.cmake) 52 | 53 | 54 | # === Installation === 55 | # Support files are copied into place next to the executable, so that it can 56 | # run in place. This is done instead of making a separate bundle (as on Linux) 57 | # so that building and running from within Visual Studio will work. 58 | set(BUILD_BUNDLE_DIR "$") 59 | # Make the "install" step default, as it's required to run. 60 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) 61 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 62 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 63 | endif() 64 | 65 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 66 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") 67 | 68 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 69 | COMPONENT Runtime) 70 | 71 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 72 | COMPONENT Runtime) 73 | 74 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 75 | COMPONENT Runtime) 76 | 77 | if(PLUGIN_BUNDLED_LIBRARIES) 78 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" 79 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 80 | COMPONENT Runtime) 81 | endif() 82 | 83 | # Fully re-copy the assets directory on each build to avoid having stale files 84 | # from a previous install. 85 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 86 | install(CODE " 87 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 88 | " COMPONENT Runtime) 89 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 90 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 91 | 92 | # Install the AOT library on non-Debug builds only. 93 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 94 | CONFIGURATIONS Profile;Release 95 | COMPONENT Runtime) 96 | -------------------------------------------------------------------------------- /windows/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 4 | 5 | # Configuration provided via flutter tool. 6 | include(${EPHEMERAL_DIR}/generated_config.cmake) 7 | 8 | # TODO: Move the rest of this into files in ephemeral. See 9 | # https://github.com/flutter/flutter/issues/57146. 10 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") 11 | 12 | # === Flutter Library === 13 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") 14 | 15 | # Published to parent scope for install step. 16 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 17 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 18 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 19 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) 20 | 21 | list(APPEND FLUTTER_LIBRARY_HEADERS 22 | "flutter_export.h" 23 | "flutter_windows.h" 24 | "flutter_messenger.h" 25 | "flutter_plugin_registrar.h" 26 | "flutter_texture_registrar.h" 27 | ) 28 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") 29 | add_library(flutter INTERFACE) 30 | target_include_directories(flutter INTERFACE 31 | "${EPHEMERAL_DIR}" 32 | ) 33 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") 34 | add_dependencies(flutter flutter_assemble) 35 | 36 | # === Wrapper === 37 | list(APPEND CPP_WRAPPER_SOURCES_CORE 38 | "core_implementations.cc" 39 | "standard_codec.cc" 40 | ) 41 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") 42 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN 43 | "plugin_registrar.cc" 44 | ) 45 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") 46 | list(APPEND CPP_WRAPPER_SOURCES_APP 47 | "flutter_engine.cc" 48 | "flutter_view_controller.cc" 49 | ) 50 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") 51 | 52 | # Wrapper sources needed for a plugin. 53 | add_library(flutter_wrapper_plugin STATIC 54 | ${CPP_WRAPPER_SOURCES_CORE} 55 | ${CPP_WRAPPER_SOURCES_PLUGIN} 56 | ) 57 | apply_standard_settings(flutter_wrapper_plugin) 58 | set_target_properties(flutter_wrapper_plugin PROPERTIES 59 | POSITION_INDEPENDENT_CODE ON) 60 | set_target_properties(flutter_wrapper_plugin PROPERTIES 61 | CXX_VISIBILITY_PRESET hidden) 62 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) 63 | target_include_directories(flutter_wrapper_plugin PUBLIC 64 | "${WRAPPER_ROOT}/include" 65 | ) 66 | add_dependencies(flutter_wrapper_plugin flutter_assemble) 67 | 68 | # Wrapper sources needed for the runner. 69 | add_library(flutter_wrapper_app STATIC 70 | ${CPP_WRAPPER_SOURCES_CORE} 71 | ${CPP_WRAPPER_SOURCES_APP} 72 | ) 73 | apply_standard_settings(flutter_wrapper_app) 74 | target_link_libraries(flutter_wrapper_app PUBLIC flutter) 75 | target_include_directories(flutter_wrapper_app PUBLIC 76 | "${WRAPPER_ROOT}/include" 77 | ) 78 | add_dependencies(flutter_wrapper_app flutter_assemble) 79 | 80 | # === Flutter tool backend === 81 | # _phony_ is a non-existent file to force this command to run every time, 82 | # since currently there's no way to get a full input/output list from the 83 | # flutter tool. 84 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") 85 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) 86 | add_custom_command( 87 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 88 | ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} 89 | ${CPP_WRAPPER_SOURCES_APP} 90 | ${PHONY_OUTPUT} 91 | COMMAND ${CMAKE_COMMAND} -E env 92 | ${FLUTTER_TOOL_ENVIRONMENT} 93 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" 94 | windows-x64 $ 95 | VERBATIM 96 | ) 97 | add_custom_target(flutter_assemble DEPENDS 98 | "${FLUTTER_LIBRARY}" 99 | ${FLUTTER_LIBRARY_HEADERS} 100 | ${CPP_WRAPPER_SOURCES_CORE} 101 | ${CPP_WRAPPER_SOURCES_PLUGIN} 102 | ${CPP_WRAPPER_SOURCES_APP} 103 | ) 104 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | void RegisterPlugins(flutter::PluginRegistry* registry) { 14 | BitsdojoWindowPluginRegisterWithRegistrar( 15 | registry->GetRegistrarForPlugin("BitsdojoWindowPlugin")); 16 | FlutterAcrylicPluginRegisterWithRegistrar( 17 | registry->GetRegistrarForPlugin("FlutterAcrylicPlugin")); 18 | SystemThemePluginRegisterWithRegistrar( 19 | registry->GetRegistrarForPlugin("SystemThemePlugin")); 20 | } 21 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | bitsdojo_window_windows 7 | flutter_acrylic 8 | system_theme 9 | ) 10 | 11 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 12 | ) 13 | 14 | set(PLUGIN_BUNDLED_LIBRARIES) 15 | 16 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 17 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 18 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 20 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 21 | endforeach(plugin) 22 | 23 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 24 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 26 | endforeach(ffi_plugin) 27 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(runner LANGUAGES CXX) 3 | 4 | add_executable(${BINARY_NAME} WIN32 5 | "flutter_window.cpp" 6 | "main.cpp" 7 | "utils.cpp" 8 | "win32_window.cpp" 9 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 10 | "Runner.rc" 11 | "runner.exe.manifest" 12 | ) 13 | 14 | apply_standard_settings(${BINARY_NAME}) 15 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 16 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 17 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 18 | add_dependencies(${BINARY_NAME} flutter_assemble) 19 | -------------------------------------------------------------------------------- /windows/runner/Runner.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #pragma code_page(65001) 4 | #include "resource.h" 5 | 6 | #define APSTUDIO_READONLY_SYMBOLS 7 | ///////////////////////////////////////////////////////////////////////////// 8 | // 9 | // Generated from the TEXTINCLUDE 2 resource. 10 | // 11 | #include "winres.h" 12 | 13 | ///////////////////////////////////////////////////////////////////////////// 14 | #undef APSTUDIO_READONLY_SYMBOLS 15 | 16 | ///////////////////////////////////////////////////////////////////////////// 17 | // English (United States) resources 18 | 19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Icon 51 | // 52 | 53 | // Icon with lowest ID value placed first to ensure application icon 54 | // remains consistent on all systems. 55 | IDI_APP_ICON ICON "resources\\app_icon.ico" 56 | 57 | 58 | ///////////////////////////////////////////////////////////////////////////// 59 | // 60 | // Version 61 | // 62 | 63 | #ifdef FLUTTER_BUILD_NUMBER 64 | #define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER 65 | #else 66 | #define VERSION_AS_NUMBER 1,0,0,3 67 | #endif 68 | 69 | #ifdef FLUTTER_BUILD_NAME 70 | #define VERSION_AS_STRING #FLUTTER_BUILD_NAME 71 | #else 72 | #define VERSION_AS_STRING "1.0.0.3" 73 | #endif 74 | 75 | VS_VERSION_INFO VERSIONINFO 76 | FILEVERSION VERSION_AS_NUMBER 77 | PRODUCTVERSION VERSION_AS_NUMBER 78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 79 | #ifdef _DEBUG 80 | FILEFLAGS VS_FF_DEBUG 81 | #else 82 | FILEFLAGS 0x0L 83 | #endif 84 | FILEOS VOS__WINDOWS32 85 | FILETYPE VFT_APP 86 | FILESUBTYPE 0x0L 87 | BEGIN 88 | BLOCK "StringFileInfo" 89 | BEGIN 90 | BLOCK "040904e4" 91 | BEGIN 92 | VALUE "CompanyName", "com.wsa_pacman" "\0" 93 | VALUE "FileDescription", "WSA Package Manager" "\0" 94 | VALUE "FileVersion", VERSION_AS_STRING "\0" 95 | VALUE "InternalName", "wsa_pacman" "\0" 96 | VALUE "LegalCopyright", "Copyright (C) 2021 com.wsa_pacman. All rights reserved." "\0" 97 | VALUE "OriginalFilename", "WSA-pacman.exe" "\0" 98 | VALUE "ProductName", "WSA Package Manager" "\0" 99 | VALUE "ProductVersion", VERSION_AS_STRING "\0" 100 | END 101 | END 102 | BLOCK "VarFileInfo" 103 | BEGIN 104 | VALUE "Translation", 0x409, 1252 105 | END 106 | END 107 | 108 | #endif // English (United States) resources 109 | ///////////////////////////////////////////////////////////////////////////// 110 | 111 | 112 | 113 | #ifndef APSTUDIO_INVOKED 114 | ///////////////////////////////////////////////////////////////////////////// 115 | // 116 | // Generated from the TEXTINCLUDE 3 resource. 117 | // 118 | 119 | 120 | ///////////////////////////////////////////////////////////////////////////// 121 | #endif // not APSTUDIO_INVOKED 122 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | return true; 30 | } 31 | 32 | void FlutterWindow::OnDestroy() { 33 | if (flutter_controller_) { 34 | flutter_controller_ = nullptr; 35 | } 36 | 37 | Win32Window::OnDestroy(); 38 | } 39 | 40 | LRESULT 41 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 42 | WPARAM const wparam, 43 | LPARAM const lparam) noexcept { 44 | // Give Flutter, including plugins, an opportunity to handle window messages. 45 | if (flutter_controller_) { 46 | std::optional result = 47 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 48 | lparam); 49 | if (result) { 50 | return *result; 51 | } 52 | } 53 | 54 | switch (message) { 55 | case WM_FONTCHANGE: 56 | flutter_controller_->engine()->ReloadSystemFonts(); 57 | break; 58 | } 59 | 60 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 61 | } 62 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | #include 9 | auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP); 10 | 11 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 12 | _In_ wchar_t *command_line, _In_ int show_command) { 13 | 14 | //Prevent conosole instances from popping up when running a process with Process.run after launching the executable 15 | //Solution: https://github.com/flutter/flutter/issues/47891#issuecomment-708850435 16 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {CreateAndAttachConsole();} else { 17 | STARTUPINFO si = { 0 }; 18 | si.cb = sizeof(si); 19 | si.dwFlags = STARTF_USESHOWWINDOW; 20 | si.wShowWindow = SW_HIDE; 21 | 22 | PROCESS_INFORMATION pi = { 0 }; 23 | WCHAR lpszCmd[MAX_PATH] = L"cmd.exe"; 24 | if (::CreateProcess(NULL, lpszCmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { 25 | do { 26 | if (::AttachConsole(pi.dwProcessId)) { 27 | ::TerminateProcess(pi.hProcess, 0); 28 | break; 29 | } 30 | } while (ERROR_INVALID_HANDLE == GetLastError()); 31 | ::CloseHandle(pi.hProcess); 32 | ::CloseHandle(pi.hThread); 33 | } 34 | } 35 | 36 | // Attach to console when present (e.g., 'flutter run') or create a 37 | // new console when running with a debugger. 38 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 39 | CreateAndAttachConsole(); 40 | } 41 | 42 | // Initialize COM, so that it is available for use in the library and/or 43 | // plugins. 44 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 45 | 46 | flutter::DartProject project(L"data"); 47 | 48 | std::vector command_line_arguments = 49 | GetCommandLineArguments(); 50 | 51 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 52 | 53 | FlutterWindow window(project); 54 | Win32Window::Point origin(10, 10); 55 | Win32Window::Size size(1280, 720); 56 | if (!window.CreateAndShow(L"wsa_pacman", origin, size)) { 57 | return EXIT_FAILURE; 58 | } 59 | window.SetQuitOnClose(true); 60 | 61 | ::MSG msg; 62 | while (::GetMessage(&msg, nullptr, 0, 0)) { 63 | ::TranslateMessage(&msg); 64 | ::DispatchMessage(&msg); 65 | } 66 | 67 | ::CoUninitialize(); 68 | return EXIT_SUCCESS; 69 | } 70 | -------------------------------------------------------------------------------- /windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /windows/runner/run_loop.cpp: -------------------------------------------------------------------------------- 1 | #include "run_loop.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | RunLoop::RunLoop() {} 8 | 9 | RunLoop::~RunLoop() {} 10 | 11 | void RunLoop::Run() { 12 | bool keep_running = true; 13 | TimePoint next_flutter_event_time = TimePoint::clock::now(); 14 | while (keep_running) { 15 | std::chrono::nanoseconds wait_duration = 16 | std::max(std::chrono::nanoseconds(0), 17 | next_flutter_event_time - TimePoint::clock::now()); 18 | ::MsgWaitForMultipleObjects( 19 | 0, nullptr, FALSE, static_cast(wait_duration.count() / 1000), 20 | QS_ALLINPUT); 21 | bool processed_events = false; 22 | MSG message; 23 | // All pending Windows messages must be processed; MsgWaitForMultipleObjects 24 | // won't return again for items left in the queue after PeekMessage. 25 | while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) { 26 | processed_events = true; 27 | if (message.message == WM_QUIT) { 28 | keep_running = false; 29 | break; 30 | } 31 | ::TranslateMessage(&message); 32 | ::DispatchMessage(&message); 33 | // Allow Flutter to process messages each time a Windows message is 34 | // processed, to prevent starvation. 35 | next_flutter_event_time = 36 | std::min(next_flutter_event_time, ProcessFlutterMessages()); 37 | } 38 | // If the PeekMessage loop didn't run, process Flutter messages. 39 | if (!processed_events) { 40 | next_flutter_event_time = 41 | std::min(next_flutter_event_time, ProcessFlutterMessages()); 42 | } 43 | } 44 | } 45 | 46 | void RunLoop::RegisterFlutterInstance( 47 | flutter::FlutterEngine* flutter_instance) { 48 | flutter_instances_.insert(flutter_instance); 49 | } 50 | 51 | void RunLoop::UnregisterFlutterInstance( 52 | flutter::FlutterEngine* flutter_instance) { 53 | flutter_instances_.erase(flutter_instance); 54 | } 55 | 56 | RunLoop::TimePoint RunLoop::ProcessFlutterMessages() { 57 | TimePoint next_event_time = TimePoint::max(); 58 | for (auto instance : flutter_instances_) { 59 | std::chrono::nanoseconds wait_duration = instance->ProcessMessages(); 60 | if (wait_duration != std::chrono::nanoseconds::max()) { 61 | next_event_time = 62 | std::min(next_event_time, TimePoint::clock::now() + wait_duration); 63 | } 64 | } 65 | return next_event_time; 66 | } 67 | -------------------------------------------------------------------------------- /windows/runner/run_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_RUN_LOOP_H_ 2 | #define RUNNER_RUN_LOOP_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | // A runloop that will service events for Flutter instances as well 10 | // as native messages. 11 | class RunLoop { 12 | public: 13 | RunLoop(); 14 | ~RunLoop(); 15 | 16 | // Prevent copying 17 | RunLoop(RunLoop const&) = delete; 18 | RunLoop& operator=(RunLoop const&) = delete; 19 | 20 | // Runs the run loop until the application quits. 21 | void Run(); 22 | 23 | // Registers the given Flutter instance for event servicing. 24 | void RegisterFlutterInstance( 25 | flutter::FlutterEngine* flutter_instance); 26 | 27 | // Unregisters the given Flutter instance from event servicing. 28 | void UnregisterFlutterInstance( 29 | flutter::FlutterEngine* flutter_instance); 30 | 31 | private: 32 | using TimePoint = std::chrono::steady_clock::time_point; 33 | 34 | // Processes all currently pending messages for registered Flutter instances. 35 | TimePoint ProcessFlutterMessages(); 36 | 37 | std::set flutter_instances_; 38 | }; 39 | 40 | #endif // RUNNER_RUN_LOOP_H_ 41 | -------------------------------------------------------------------------------- /windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr); 51 | if (target_length == 0) { 52 | return std::string(); 53 | } 54 | std::string utf8_string; 55 | utf8_string.resize(target_length); 56 | int converted_length = ::WideCharToMultiByte( 57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 58 | -1, utf8_string.data(), 59 | target_length, nullptr, nullptr); 60 | if (converted_length == 0) { 61 | return std::string(); 62 | } 63 | return utf8_string; 64 | } 65 | -------------------------------------------------------------------------------- /windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /windows/runner/win32_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_WIN32_WINDOW_H_ 2 | #define RUNNER_WIN32_WINDOW_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be 11 | // inherited from by classes that wish to specialize with custom 12 | // rendering and input handling 13 | class Win32Window { 14 | public: 15 | struct Point { 16 | unsigned int x; 17 | unsigned int y; 18 | Point(unsigned int x, unsigned int y) : x(x), y(y) {} 19 | }; 20 | 21 | struct Size { 22 | unsigned int width; 23 | unsigned int height; 24 | Size(unsigned int width, unsigned int height) 25 | : width(width), height(height) {} 26 | }; 27 | 28 | Win32Window(); 29 | virtual ~Win32Window(); 30 | 31 | // Creates and shows a win32 window with |title| and position and size using 32 | // |origin| and |size|. New windows are created on the default monitor. Window 33 | // sizes are specified to the OS in physical pixels, hence to ensure a 34 | // consistent size to will treat the width height passed in to this function 35 | // as logical pixels and scale to appropriate for the default monitor. Returns 36 | // true if the window was created successfully. 37 | bool CreateAndShow(const std::wstring& title, 38 | const Point& origin, 39 | const Size& size); 40 | 41 | // Release OS resources associated with window. 42 | void Destroy(); 43 | 44 | // Inserts |content| into the window tree. 45 | void SetChildContent(HWND content); 46 | 47 | // Returns the backing Window handle to enable clients to set icon and other 48 | // window properties. Returns nullptr if the window has been destroyed. 49 | HWND GetHandle(); 50 | 51 | // If true, closing this window will quit the application. 52 | void SetQuitOnClose(bool quit_on_close); 53 | 54 | // Return a RECT representing the bounds of the current client area. 55 | RECT GetClientArea(); 56 | 57 | protected: 58 | // Processes and route salient window messages for mouse handling, 59 | // size change and DPI. Delegates handling of these to member overloads that 60 | // inheriting classes can handle. 61 | virtual LRESULT MessageHandler(HWND window, 62 | UINT const message, 63 | WPARAM const wparam, 64 | LPARAM const lparam) noexcept; 65 | 66 | // Called when CreateAndShow is called, allowing subclass window-related 67 | // setup. Subclasses should return false if setup fails. 68 | virtual bool OnCreate(); 69 | 70 | // Called when Destroy is called. 71 | virtual void OnDestroy(); 72 | 73 | private: 74 | friend class WindowClassRegistrar; 75 | 76 | // OS callback called by message pump. Handles the WM_NCCREATE message which 77 | // is passed when the non-client area is being created and enables automatic 78 | // non-client DPI scaling so that the non-client area automatically 79 | // responsponds to changes in DPI. All other messages are handled by 80 | // MessageHandler. 81 | static LRESULT CALLBACK WndProc(HWND const window, 82 | UINT const message, 83 | WPARAM const wparam, 84 | LPARAM const lparam) noexcept; 85 | 86 | // Retrieves a class instance pointer for |window| 87 | static Win32Window* GetThisFromHandle(HWND const window) noexcept; 88 | 89 | bool quit_on_close_ = false; 90 | 91 | // window handle for top level window. 92 | HWND window_handle_ = nullptr; 93 | 94 | // window handle for hosted content. 95 | HWND child_content_ = nullptr; 96 | }; 97 | 98 | #endif // RUNNER_WIN32_WINDOW_H_ 99 | -------------------------------------------------------------------------------- /winuwp/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /winuwp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | set(CMAKE_SYSTEM_NAME WindowsStore) 3 | set(CMAKE_SYSTEM_VERSION 10.0) 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_CXX_STANDARD_REQUIRED YES) 6 | 7 | project(wsa_pacman LANGUAGES CXX) 8 | 9 | cmake_policy(SET CMP0079 NEW) 10 | 11 | set(BINARY_NAME "wsa_pacman") 12 | 13 | # Configure build options. 14 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 15 | if(IS_MULTICONFIG) 16 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" 17 | CACHE STRING "" FORCE) 18 | else() 19 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 20 | set(CMAKE_BUILD_TYPE "Debug" CACHE 21 | STRING "Flutter build mode" FORCE) 22 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 23 | "Debug" "Profile" "Release") 24 | endif() 25 | endif() 26 | 27 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") 28 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") 29 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") 30 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") 31 | 32 | # Use Unicode for all projects. 33 | add_definitions(-DUNICODE -D_UNICODE) 34 | 35 | # Compilation settings that should be applied to most targets. 36 | function(APPLY_STANDARD_SETTINGS TARGET) 37 | target_compile_features(${TARGET} PUBLIC cxx_std_17) 38 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100" /await) 39 | target_compile_options(${TARGET} PRIVATE /EHsc) 40 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") 41 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") 42 | target_compile_definitions(${TARGET} PRIVATE WINUWP) 43 | set_target_properties(${TARGET} PROPERTIES VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION 10.0.18362.0) 44 | endfunction() 45 | 46 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 47 | 48 | # Flutter library and tool build rules. 49 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 50 | 51 | # Application build 52 | add_subdirectory("runner_uwp") 53 | 54 | 55 | # Generated plugin build rules, which manage building the plugins and adding 56 | # them to the application. 57 | include(flutter/generated_plugins.cmake) 58 | -------------------------------------------------------------------------------- /winuwp/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | set(CMAKE_SYSTEM_NAME WindowsStore) 3 | set(CMAKE_SYSTEM_VERSION 10.0) 4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 5 | 6 | include(CMakePrintHelpers) 7 | 8 | # Configuration provided via flutter tool. 9 | include(${EPHEMERAL_DIR}/generated_config.cmake) 10 | 11 | # TODO: Move the rest of this into files in ephemeral. See 12 | # https://github.com/flutter/flutter/issues/57146. 13 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") 14 | 15 | # === Flutter Library === 16 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows_winuwp.dll") 17 | 18 | # === Assets === 19 | set(CMAKE_INSTALL_MANIFEST "${EPHEMERAL_DIR}/install_manifest") 20 | file(STRINGS ${CMAKE_INSTALL_MANIFEST} INSTALL_MANIFEST_CONTENT) 21 | 22 | # Published to parent scope for install step. 23 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 24 | set(INSTALL_MANIFEST_CONTENT ${INSTALL_MANIFEST_CONTENT} PARENT_SCOPE) 25 | 26 | list(APPEND FLUTTER_LIBRARY_HEADERS 27 | "flutter_export.h" 28 | "flutter_windows.h" 29 | "flutter_messenger.h" 30 | "flutter_plugin_registrar.h" 31 | "flutter_texture_registrar.h" 32 | ) 33 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") 34 | add_library(flutter INTERFACE) 35 | target_include_directories(flutter INTERFACE 36 | "${EPHEMERAL_DIR}" 37 | ) 38 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") 39 | add_dependencies(flutter flutter_assemble) 40 | 41 | # === Wrapper === 42 | list(APPEND CPP_WRAPPER_SOURCES_CORE 43 | "core_implementations.cc" 44 | "standard_codec.cc" 45 | ) 46 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") 47 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN 48 | "plugin_registrar.cc" 49 | ) 50 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") 51 | list(APPEND CPP_WRAPPER_SOURCES_APP 52 | "flutter_engine.cc" 53 | "flutter_view_controller.cc" 54 | ) 55 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") 56 | 57 | # Wrapper sources needed for a plugin. 58 | add_library(flutter_wrapper_plugin STATIC 59 | ${CPP_WRAPPER_SOURCES_CORE} 60 | ${CPP_WRAPPER_SOURCES_PLUGIN} 61 | ) 62 | apply_standard_settings(flutter_wrapper_plugin) 63 | set_target_properties(flutter_wrapper_plugin PROPERTIES 64 | POSITION_INDEPENDENT_CODE ON) 65 | set_target_properties(flutter_wrapper_plugin PROPERTIES 66 | CXX_VISIBILITY_PRESET hidden) 67 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) 68 | target_include_directories(flutter_wrapper_plugin PUBLIC 69 | "${WRAPPER_ROOT}/include" 70 | ) 71 | add_dependencies(flutter_wrapper_plugin flutter_assemble) 72 | 73 | # Wrapper sources needed for the runner. 74 | add_library(flutter_wrapper_app STATIC 75 | ${CPP_WRAPPER_SOURCES_CORE} 76 | ${CPP_WRAPPER_SOURCES_APP} 77 | ) 78 | apply_standard_settings(flutter_wrapper_app) 79 | target_link_libraries(flutter_wrapper_app PUBLIC flutter) 80 | target_include_directories(flutter_wrapper_app PUBLIC 81 | "${WRAPPER_ROOT}/include" 82 | ) 83 | add_dependencies(flutter_wrapper_app flutter_assemble) 84 | 85 | add_custom_target(flutter_assemble DEPENDS 86 | "${FLUTTER_LIBRARY}" 87 | ${FLUTTER_LIBRARY_HEADERS} 88 | ${CPP_WRAPPER_SOURCES_CORE} 89 | ${CPP_WRAPPER_SOURCES_PLUGIN} 90 | ${CPP_WRAPPER_SOURCES_APP} 91 | ) 92 | -------------------------------------------------------------------------------- /winuwp/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | 10 | void RegisterPlugins(flutter::PluginRegistry* registry) { 11 | } 12 | -------------------------------------------------------------------------------- /winuwp/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /winuwp/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | set(PLUGIN_BUNDLED_LIBRARIES) 9 | 10 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 11 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 12 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 13 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 14 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 15 | endforeach(plugin) 16 | -------------------------------------------------------------------------------- /winuwp/project_version: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/LargeTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/LargeTile.scale-100.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/LargeTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/LargeTile.scale-125.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/LargeTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/LargeTile.scale-150.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/LargeTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/LargeTile.scale-200.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/LargeTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/LargeTile.scale-400.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/SmallTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/SmallTile.scale-100.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/SmallTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/SmallTile.scale-125.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/SmallTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/SmallTile.scale-150.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/SmallTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/SmallTile.scale-200.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/SmallTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/SmallTile.scale-400.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/SplashScreen.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/SplashScreen.scale-100.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/SplashScreen.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/SplashScreen.scale-125.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/SplashScreen.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/SplashScreen.scale-150.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/SplashScreen.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/SplashScreen.scale-400.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square150x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square150x150Logo.scale-100.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square150x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square150x150Logo.scale-125.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square150x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square150x150Logo.scale-150.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square150x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square150x150Logo.scale-400.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-16.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-256.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-32.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-48.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.scale-100.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.scale-125.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.scale-150.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.scale-400.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-16.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-256.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-32.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-48.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/StoreLogo.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/StoreLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/StoreLogo.scale-100.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/StoreLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/StoreLogo.scale-125.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/StoreLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/StoreLogo.scale-150.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/StoreLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/StoreLogo.scale-200.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/StoreLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/StoreLogo.scale-400.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/WideTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/WideTile.scale-100.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/WideTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/WideTile.scale-125.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/WideTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/WideTile.scale-150.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/WideTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/WideTile.scale-200.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/Assets/WideTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Assets/WideTile.scale-400.png -------------------------------------------------------------------------------- /winuwp/runner_uwp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.8) 2 | set(CMAKE_SYSTEM_NAME WindowsStore) 3 | set(CMAKE_SYSTEM_VERSION 10.0) 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_CXX_STANDARD_REQUIRED YES) 6 | 7 | include(CMakePrintHelpers) 8 | 9 | project (runner LANGUAGES CXX) 10 | 11 | # UWP tile and icon assets. 12 | set(ASSET_FILES ${ASSET_FILES} 13 | Assets/LargeTile.scale-100.png 14 | Assets/LargeTile.scale-125.png 15 | Assets/LargeTile.scale-150.png 16 | Assets/LargeTile.scale-200.png 17 | Assets/LargeTile.scale-400.png 18 | Assets/LockScreenLogo.scale-200.png 19 | Assets/SmallTile.scale-100.png 20 | Assets/SmallTile.scale-125.png 21 | Assets/SmallTile.scale-150.png 22 | Assets/SmallTile.scale-200.png 23 | Assets/SmallTile.scale-400.png 24 | Assets/SplashScreen.scale-100.png 25 | Assets/SplashScreen.scale-125.png 26 | Assets/SplashScreen.scale-150.png 27 | Assets/SplashScreen.scale-200.png 28 | Assets/SplashScreen.scale-400.png 29 | Assets/Square44x44Logo.altform-unplated_targetsize-16.png 30 | Assets/Square44x44Logo.altform-unplated_targetsize-32.png 31 | Assets/Square44x44Logo.altform-unplated_targetsize-48.png 32 | Assets/Square44x44Logo.altform-unplated_targetsize-256.png 33 | Assets/Square44x44Logo.scale-100.png 34 | Assets/Square44x44Logo.scale-125.png 35 | Assets/Square44x44Logo.scale-150.png 36 | Assets/Square44x44Logo.scale-200.png 37 | Assets/Square44x44Logo.scale-400.png 38 | Assets/Square44x44Logo.targetsize-16.png 39 | Assets/Square44x44Logo.targetsize-24.png 40 | Assets/Square44x44Logo.targetsize-24_altform-unplated.png 41 | Assets/Square44x44Logo.targetsize-32.png 42 | Assets/Square44x44Logo.targetsize-48.png 43 | Assets/Square44x44Logo.targetsize-256.png 44 | Assets/Square150x150Logo.scale-100.png 45 | Assets/Square150x150Logo.scale-125.png 46 | Assets/Square150x150Logo.scale-150.png 47 | Assets/Square150x150Logo.scale-200.png 48 | Assets/Square150x150Logo.scale-400.png 49 | Assets/StoreLogo.png 50 | Assets/StoreLogo.scale-100.png 51 | Assets/StoreLogo.scale-125.png 52 | Assets/StoreLogo.scale-150.png 53 | Assets/StoreLogo.scale-200.png 54 | Assets/StoreLogo.scale-400.png 55 | Assets/Wide310x150Logo.scale-200.png 56 | Assets/WideTile.scale-100.png 57 | Assets/WideTile.scale-125.png 58 | Assets/WideTile.scale-150.png 59 | Assets/WideTile.scale-200.png 60 | Assets/WideTile.scale-400.png 61 | ) 62 | 63 | # Configure package manifest file. 64 | set(APP_MANIFEST_NAME Package.appxmanifest) 65 | set(APP_MANIFEST_TARGET_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/${APP_MANIFEST_NAME}) 66 | set(SHORT_NAME ${BINARY_NAME}) 67 | set(PACKAGE_GUID "D8EBD069-504B-4B0C-AA2B-7C0172F61791") 68 | 69 | configure_file( 70 | appxmanifest.in 71 | ${APP_MANIFEST_TARGET_LOCATION} 72 | @ONLY) 73 | 74 | set(CONTENT_FILES ${APP_MANIFEST_TARGET_LOCATION}) 75 | 76 | # Configure package content files. 77 | set_property(SOURCE ${CONTENT_FILES} PROPERTY VS_DEPLOYMENT_CONTENT 1) 78 | 79 | set(RESOURCE_FILES ${ASSET_FILES} ${CONTENT_FILES} Windows_TemporaryKey.pfx) 80 | set_property(SOURCE ${ASSET_FILES} PROPERTY VS_DEPLOYMENT_CONTENT 1) 81 | set_property(SOURCE ${ASSET_FILES} PROPERTY VS_DEPLOYMENT_LOCATION "Assets") 82 | 83 | set(STRING_FILES Resources.pri) 84 | set_property(SOURCE ${STRING_FILES} PROPERTY VS_TOOL_OVERRIDE "PRIResource") 85 | 86 | source_group("Resource Files" FILES ${RESOURCE_FILES} ${CONTENT_FILES} ${STRING_FILES}) 87 | 88 | # Configure Flutter assets using tool generated install manifest 89 | foreach(ITEM ${INSTALL_MANIFEST_CONTENT}) 90 | get_filename_component(ITEM_REL ${CMAKE_BINARY_DIR} DIRECTORY) 91 | file(RELATIVE_PATH RELPATH ${ITEM_REL} ${ITEM}) 92 | 93 | get_filename_component(RELPATH ${RELPATH} DIRECTORY) 94 | get_filename_component(ITEMEXT ${ITEM} LAST_EXT) 95 | 96 | if("${ITEMEXT}" STREQUAL ".dll" OR "${ITEMEXT}" STREQUAL ".pdb") 97 | string(CONCAT RELPATH "") 98 | elseif ("${ITEMEXT}" STREQUAL ".so") 99 | file(RELATIVE_PATH RELPATH "${ITEM_REL}/winuwp" ${ITEM}) 100 | string(REGEX REPLACE "/" "\\\\" RELPATH ${RELPATH}) 101 | string(CONCAT RELPATH "Assets\\Data") 102 | elseif("${ITEMEXT}" STREQUAL ".dat") 103 | string(CONCAT RELPATH "Assets\\Data") 104 | else() 105 | string(REGEX REPLACE "/" "\\\\" RELPATH ${RELPATH}) 106 | string(CONCAT RELPATH "Assets\\Data\\" ${RELPATH}) 107 | endif() 108 | 109 | cmake_print_variables(${RELPATH}) 110 | 111 | set_property(SOURCE ${ITEM} PROPERTY VS_DEPLOYMENT_CONTENT 1) 112 | set_property(SOURCE ${ITEM} PROPERTY VS_DEPLOYMENT_LOCATION ${RELPATH}) 113 | endforeach() 114 | 115 | add_executable (${BINARY_NAME} WIN32 116 | main.cpp 117 | flutter_frameworkview.cpp 118 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 119 | ${RESOURCE_FILES} 120 | ${INSTALL_MANIFEST_CONTENT} 121 | ) 122 | apply_standard_settings(${BINARY_NAME}) 123 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 124 | target_link_libraries(${BINARY_NAME} PRIVATE WindowsApp flutter flutter_wrapper_app) 125 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 126 | 127 | add_dependencies(${BINARY_NAME} flutter_assemble) 128 | -------------------------------------------------------------------------------- /winuwp/runner_uwp/CMakeSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file. 3 | "configurations": [ 4 | { 5 | "name": "Debug", 6 | "generator": "Visual Studio 15 2017 Win64", 7 | "configurationType": "Debug", 8 | "inheritEnvironments": [ "msvc_x64_x64" ], 9 | "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", 10 | "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", 11 | "cmakeCommandArgs": "", 12 | "buildCommandArgs": "", 13 | "ctestCommandArgs": "" 14 | }, 15 | { 16 | "name": "Release", 17 | "generator": "Visual Studio 15 2017 Win64", 18 | "configurationType": "Release", 19 | "inheritEnvironments": [ "msvc_x64_x64" ], 20 | "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", 21 | "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", 22 | "cmakeCommandArgs": "", 23 | "buildCommandArgs": "", 24 | "ctestCommandArgs": "" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /winuwp/runner_uwp/Windows_TemporaryKey.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/Windows_TemporaryKey.pfx -------------------------------------------------------------------------------- /winuwp/runner_uwp/appxmanifest.in: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | @SHORT_NAME@ 13 | CMake Test Cert 14 | Assets/StoreLogo.png 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /winuwp/runner_uwp/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "winrt/Windows.ApplicationModel.Core.h" 5 | #include "winrt/Windows.Foundation.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include "flutter_frameworkview.cpp" 13 | 14 | struct App 15 | : winrt::implements< 16 | App, winrt::Windows::ApplicationModel::Core::IFrameworkViewSource> { 17 | App() { view_ = winrt::make_self(); } 18 | 19 | // |winrt::Windows::ApplicationModel::Core::IFrameworkViewSource| 20 | winrt::Windows::ApplicationModel::Core::IFrameworkView CreateView() { 21 | return view_.as(); 22 | } 23 | 24 | winrt::com_ptr view_; 25 | }; 26 | 27 | int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { 28 | winrt::Windows::ApplicationModel::Core::CoreApplication::Run( 29 | winrt::make()); 30 | } 31 | -------------------------------------------------------------------------------- /winuwp/runner_uwp/resources.pri: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alesimula/wsa_pacman/5f5bc79a45b081879db794ce7253c36a5ec868c8/winuwp/runner_uwp/resources.pri --------------------------------------------------------------------------------