re-run flutter create (to add windows platform)

This commit is contained in:
Pato05 2023-10-19 14:34:22 +02:00
parent f126ffef46
commit 276d0ad4bf
No known key found for this signature in database
GPG Key ID: ED4C6F9C3D574FB6
104 changed files with 7331 additions and 7327 deletions

View File

@ -1,11 +1,11 @@
# This file tracks properties of this Flutter project. # This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc. # Used by Flutter tool to assess capabilities and perform upgrades etc.
# #
# This file should be version controlled. # This file should be version controlled and should not be manually edited.
version: version:
revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 revision: "2f708eb8396e362e280fac22cf171c2cb467343c"
channel: stable channel: "stable"
project_type: app project_type: app
@ -13,26 +13,20 @@ project_type: app
migration: migration:
platforms: platforms:
- platform: root - platform: root
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
- platform: android
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: ios - platform: ios
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
- platform: linux - platform: linux
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
- platform: macos - platform: macos
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
- platform: web
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: windows - platform: windows
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: 2f708eb8396e362e280fac22cf171c2cb467343c
# User provided section # User provided section

View File

@ -1,31 +1,31 @@
# This file configures the analyzer, which statically analyzes Dart code to # This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints. # check for errors, warnings, and lints.
# #
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`. # invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps, # The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices. # packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml include: package:flutter_lints/flutter.yaml
linter: linter:
# The lint rules applied to this project can be customized in the # The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml` # section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints # included above or to enable additional rules. A list of all available lints
# and their documentation is published at # and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html. # https://dart-lang.github.io/linter/lints/index.html.
# #
# Instead of disabling a lint rule for the entire project in the # Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code # section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and # or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file # `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint. # producing the lint.
rules: rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule # avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
constant_identifier_names: false # too much constant_identifier_names: false # too much
use_build_context_synchronously: false # no use_build_context_synchronously: false # no
# Additional information about this file can be found at # Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options # https://dart.dev/guides/language/analysis-options

View File

@ -1,6 +1,6 @@
package f.f.freezer package f.f.freezer
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() { class MainActivity: FlutterActivity() {
} }

View File

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="960" android:viewportWidth="960"
android:viewportHeight="960"> android:viewportHeight="960">
<path <path
android:fillColor="#FFFFFFFF" android:fillColor="#FFFFFFFF"
android:pathData="M300,640v-60h100v-40h-60v-40h60v-40L300,460v-60h120q17,0 28.5,11.5T460,440v160q0,17 -11.5,28.5T420,640L300,640ZM540,640q-17,0 -28.5,-11.5T500,600v-160q0,-17 11.5,-28.5T540,400h80q17,0 28.5,11.5T660,440v160q0,17 -11.5,28.5T620,640h-80ZM560,580h40v-120h-40v120ZM480,880q-75,0 -140.5,-28.5t-114,-77q-48.5,-48.5 -77,-114T120,520q0,-75 28.5,-140.5t77,-114q48.5,-48.5 114,-77T480,160h6l-62,-62 56,-58 160,160 -160,160 -56,-58 62,-62h-6q-117,0 -198.5,81.5T200,520q0,117 81.5,198.5T480,800q117,0 198.5,-81.5T760,520h80q0,75 -28.5,140.5t-77,114q-48.5,48.5 -114,77T480,880Z"/> android:pathData="M300,640v-60h100v-40h-60v-40h60v-40L300,460v-60h120q17,0 28.5,11.5T460,440v160q0,17 -11.5,28.5T420,640L300,640ZM540,640q-17,0 -28.5,-11.5T500,600v-160q0,-17 11.5,-28.5T540,400h80q17,0 28.5,11.5T660,440v160q0,17 -11.5,28.5T620,640h-80ZM560,580h40v-120h-40v120ZM480,880q-75,0 -140.5,-28.5t-114,-77q-48.5,-48.5 -77,-114T120,520q0,-75 28.5,-140.5t77,-114q48.5,-48.5 114,-77T480,160h6l-62,-62 56,-58 160,160 -160,160 -56,-58 62,-62h-6q-117,0 -198.5,81.5T200,520q0,117 81.5,198.5T480,800q117,0 198.5,-81.5T760,520h80q0,75 -28.5,140.5t-77,114q-48.5,48.5 -114,77T480,880Z"/>
</vector> </vector>

View File

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="960" android:viewportWidth="960"
android:viewportHeight="960"> android:viewportHeight="960">
<path <path
android:fillColor="#FFFFFFFF" android:fillColor="#FFFFFFFF"
android:pathData="m480,840 l-58,-52q-101,-91 -167,-157T150,512.5Q111,460 95.5,416T80,326q0,-94 63,-157t157,-63q52,0 99,22t81,62q34,-40 81,-62t99,-22q94,0 157,63t63,157q0,46 -15.5,90T810,512.5Q771,565 705,631T538,788l-58,52ZM480,732q96,-86 158,-147.5t98,-107q36,-45.5 50,-81t14,-70.5q0,-60 -40,-100t-100,-40q-47,0 -87,26.5T518,280h-76q-15,-41 -55,-67.5T300,186q-60,0 -100,40t-40,100q0,35 14,70.5t50,81q36,45.5 98,107T480,732ZM480,459Z"/> android:pathData="m480,840 l-58,-52q-101,-91 -167,-157T150,512.5Q111,460 95.5,416T80,326q0,-94 63,-157t157,-63q52,0 99,22t81,62q34,-40 81,-62t99,-22q94,0 157,63t63,157q0,46 -15.5,90T810,512.5Q771,565 705,631T538,788l-58,52ZM480,732q96,-86 158,-147.5t98,-107q36,-45.5 50,-81t14,-70.5q0,-60 -40,-100t-100,-40q-47,0 -87,26.5T518,280h-76q-15,-41 -55,-67.5T300,186q-60,0 -100,40t-40,100q0,35 14,70.5t50,81q36,45.5 98,107T480,732ZM480,459Z"/>
</vector> </vector>

View File

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="960" android:viewportWidth="960"
android:viewportHeight="960"> android:viewportHeight="960">
<path <path
android:fillColor="#FFFFFFFF" android:fillColor="#FFFFFFFF"
android:pathData="M480,880q-75,0 -140.5,-28.5t-114,-77q-48.5,-48.5 -77,-114T120,520h80q0,117 81.5,198.5T480,800q117,0 198.5,-81.5T760,520q0,-117 -81.5,-198.5T480,240h-6l62,62 -56,58 -160,-160 160,-160 56,58 -62,62h6q75,0 140.5,28.5t114,77q48.5,48.5 77,114T840,520q0,75 -28.5,140.5t-77,114q-48.5,48.5 -114,77T480,880ZM300,640v-60h100v-40h-60v-40h60v-40L300,460v-60h120q17,0 28.5,11.5T460,440v160q0,17 -11.5,28.5T420,640L300,640ZM540,640q-17,0 -28.5,-11.5T500,600v-160q0,-17 11.5,-28.5T540,400h80q17,0 28.5,11.5T660,440v160q0,17 -11.5,28.5T620,640h-80ZM560,580h40v-120h-40v120Z"/> android:pathData="M480,880q-75,0 -140.5,-28.5t-114,-77q-48.5,-48.5 -77,-114T120,520h80q0,117 81.5,198.5T480,800q117,0 198.5,-81.5T760,520q0,-117 -81.5,-198.5T480,240h-6l62,62 -56,58 -160,-160 160,-160 56,58 -62,62h6q75,0 140.5,28.5t114,77q48.5,48.5 77,114T840,520q0,75 -28.5,140.5t-77,114q-48.5,48.5 -114,77T480,880ZM300,640v-60h100v-40h-60v-40h60v-40L300,460v-60h120q17,0 28.5,11.5T460,440v160q0,17 -11.5,28.5T420,640L300,640ZM540,640q-17,0 -28.5,-11.5T500,600v-160q0,-17 11.5,-28.5T540,400h80q17,0 28.5,11.5T660,440v160q0,17 -11.5,28.5T620,640h-80ZM560,580h40v-120h-40v120Z"/>
</vector> </vector>

View File

@ -1,29 +1,29 @@
buildscript { buildscript {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.4.2' classpath 'com.android.tools.build:gradle:7.4.2'
} }
} }
allprojects { allprojects {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
} }
rootProject.buildDir = '../build' rootProject.buildDir = '../build'
subprojects { subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}" project.buildDir = "${rootProject.buildDir}/${project.name}"
} }
subprojects { subprojects {
project.evaluationDependsOn(':app') project.evaluationDependsOn(':app')
} }
tasks.register("clean", Delete) { tasks.register("clean", Delete) {
delete rootProject.buildDir delete rootProject.buildDir
} }

View File

@ -1,6 +1,6 @@
targets: targets:
$default: $default:
builders: builders:
json_serializable: json_serializable:
options: options:
explicit_to_json: true explicit_to_json: true

View File

@ -1,30 +1,30 @@
# Miscellaneous # Miscellaneous
*.class *.class
*.log *.log
*.pyc *.pyc
*.swp *.swp
.DS_Store .DS_Store
.atom/ .atom/
.buildlog/ .buildlog/
.history .history
.svn/ .svn/
migrate_working_dir/ migrate_working_dir/
# IntelliJ related # IntelliJ related
*.iml *.iml
*.ipr *.ipr
*.iws *.iws
.idea/ .idea/
# The .vscode folder contains launch configuration and tasks you configure in # The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line # VS Code which you may wish to be included in version control, so this line
# is commented out by default. # is commented out by default.
#.vscode/ #.vscode/
# Flutter/Dart/Pub related # Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock /pubspec.lock
**/doc/api/ **/doc/api/
.dart_tool/ .dart_tool/
.packages .packages
build/ build/

View File

@ -1,42 +1,42 @@
# This file tracks properties of this Flutter project. # This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc. # Used by Flutter tool to assess capabilities and perform upgrades etc.
# #
# This file should be version controlled. # This file should be version controlled.
version: version:
revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
channel: stable channel: stable
project_type: plugin_ffi project_type: plugin_ffi
# Tracks metadata for the flutter migrate command # Tracks metadata for the flutter migrate command
migration: migration:
platforms: platforms:
- platform: root - platform: root
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: android - platform: android
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: ios - platform: ios
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: linux - platform: linux
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: macos - platform: macos
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: windows - platform: windows
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
# User provided section # User provided section
# List of Local paths (relative to this file) that should be # List of Local paths (relative to this file) that should be
# ignored by the migrate tool. # ignored by the migrate tool.
# #
# Files that are not part of the templates will be ignored by default. # Files that are not part of the templates will be ignored by default.
unmanaged_files: unmanaged_files:
- 'lib/main.dart' - 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj' - 'ios/Runner.xcodeproj/project.pbxproj'

View File

@ -1,3 +1,3 @@
## 0.0.1 ## 0.0.1
* TODO: Describe initial release. * TODO: Describe initial release.

View File

@ -1 +1 @@
TODO: Add your license here. TODO: Add your license here.

View File

@ -1,92 +1,92 @@
# deezcryptor # deezcryptor
A new Flutter FFI plugin project. A new Flutter FFI plugin project.
## Getting Started ## Getting Started
This project is a starting point for a Flutter This project is a starting point for a Flutter
[FFI plugin](https://docs.flutter.dev/development/platform-integration/c-interop), [FFI plugin](https://docs.flutter.dev/development/platform-integration/c-interop),
a specialized package that includes native code directly invoked with Dart FFI. a specialized package that includes native code directly invoked with Dart FFI.
## Project structure ## Project structure
This template uses the following structure: This template uses the following structure:
* `src`: Contains the native source code, and a CmakeFile.txt file for building * `src`: Contains the native source code, and a CmakeFile.txt file for building
that source code into a dynamic library. that source code into a dynamic library.
* `lib`: Contains the Dart code that defines the API of the plugin, and which * `lib`: Contains the Dart code that defines the API of the plugin, and which
calls into the native code using `dart:ffi`. calls into the native code using `dart:ffi`.
* platform folders (`android`, `ios`, `windows`, etc.): Contains the build files * platform folders (`android`, `ios`, `windows`, etc.): Contains the build files
for building and bundling the native code library with the platform application. for building and bundling the native code library with the platform application.
## Building and bundling native code ## Building and bundling native code
The `pubspec.yaml` specifies FFI plugins as follows: The `pubspec.yaml` specifies FFI plugins as follows:
```yaml ```yaml
plugin: plugin:
platforms: platforms:
some_platform: some_platform:
ffiPlugin: true ffiPlugin: true
``` ```
This configuration invokes the native build for the various target platforms This configuration invokes the native build for the various target platforms
and bundles the binaries in Flutter applications using these FFI plugins. and bundles the binaries in Flutter applications using these FFI plugins.
This can be combined with dartPluginClass, such as when FFI is used for the This can be combined with dartPluginClass, such as when FFI is used for the
implementation of one platform in a federated plugin: implementation of one platform in a federated plugin:
```yaml ```yaml
plugin: plugin:
implements: some_other_plugin implements: some_other_plugin
platforms: platforms:
some_platform: some_platform:
dartPluginClass: SomeClass dartPluginClass: SomeClass
ffiPlugin: true ffiPlugin: true
``` ```
A plugin can have both FFI and method channels: A plugin can have both FFI and method channels:
```yaml ```yaml
plugin: plugin:
platforms: platforms:
some_platform: some_platform:
pluginClass: SomeName pluginClass: SomeName
ffiPlugin: true ffiPlugin: true
``` ```
The native build systems that are invoked by FFI (and method channel) plugins are: The native build systems that are invoked by FFI (and method channel) plugins are:
* For Android: Gradle, which invokes the Android NDK for native builds. * For Android: Gradle, which invokes the Android NDK for native builds.
* See the documentation in android/build.gradle. * See the documentation in android/build.gradle.
* For iOS and MacOS: Xcode, via CocoaPods. * For iOS and MacOS: Xcode, via CocoaPods.
* See the documentation in ios/deezcryptor.podspec. * See the documentation in ios/deezcryptor.podspec.
* See the documentation in macos/deezcryptor.podspec. * See the documentation in macos/deezcryptor.podspec.
* For Linux and Windows: CMake. * For Linux and Windows: CMake.
* See the documentation in linux/CMakeLists.txt. * See the documentation in linux/CMakeLists.txt.
* See the documentation in windows/CMakeLists.txt. * See the documentation in windows/CMakeLists.txt.
## Binding to native code ## Binding to native code
To use the native code, bindings in Dart are needed. To use the native code, bindings in Dart are needed.
To avoid writing these by hand, they are generated from the header file To avoid writing these by hand, they are generated from the header file
(`src/deezcryptor.h`) by `package:ffigen`. (`src/deezcryptor.h`) by `package:ffigen`.
Regenerate the bindings by running `flutter pub run ffigen --config ffigen.yaml`. Regenerate the bindings by running `flutter pub run ffigen --config ffigen.yaml`.
## Invoking native code ## Invoking native code
Very short-running native functions can be directly invoked from any isolate. Very short-running native functions can be directly invoked from any isolate.
For example, see `sum` in `lib/deezcryptor.dart`. For example, see `sum` in `lib/deezcryptor.dart`.
Longer-running functions should be invoked on a helper isolate to avoid Longer-running functions should be invoked on a helper isolate to avoid
dropping frames in Flutter applications. dropping frames in Flutter applications.
For example, see `sumAsync` in `lib/deezcryptor.dart`. For example, see `sumAsync` in `lib/deezcryptor.dart`.
## Flutter help ## Flutter help
For help getting started with Flutter, view our For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials, [online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference. samples, guidance on mobile development, and a full API reference.

View File

@ -1,4 +1,4 @@
include: package:flutter_lints/flutter.yaml include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at # Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options # https://dart.dev/guides/language/analysis-options

View File

@ -1,9 +1,9 @@
*.iml *.iml
.gradle .gradle
/local.properties /local.properties
/.idea/workspace.xml /.idea/workspace.xml
/.idea/libraries /.idea/libraries
.DS_Store .DS_Store
/build /build
/captures /captures
.cxx .cxx

View File

@ -1,59 +1,59 @@
// The Android Gradle Plugin builds the native code with the Android NDK. // The Android Gradle Plugin builds the native code with the Android NDK.
group 'com.example.deezcryptor' group 'com.example.deezcryptor'
version '1.0' version '1.0'
buildscript { buildscript {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
// The Android Gradle Plugin knows how to build native code with the NDK. // The Android Gradle Plugin knows how to build native code with the NDK.
classpath 'com.android.tools.build:gradle:7.3.0' classpath 'com.android.tools.build:gradle:7.3.0'
} }
} }
rootProject.allprojects { rootProject.allprojects {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
} }
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
android { android {
// Bumping the plugin compileSdkVersion requires all clients of this plugin // Bumping the plugin compileSdkVersion requires all clients of this plugin
// to bump the version in their app. // to bump the version in their app.
compileSdkVersion 31 compileSdkVersion 31
// Bumping the plugin ndkVersion requires all clients of this plugin to bump // Bumping the plugin ndkVersion requires all clients of this plugin to bump
// the version in their app and to download a newer version of the NDK. // the version in their app and to download a newer version of the NDK.
// ndkVersion "25.2.9519653" // ndkVersion "25.2.9519653"
// Invoke the shared CMake build with the Android Gradle Plugin. // Invoke the shared CMake build with the Android Gradle Plugin.
externalNativeBuild { externalNativeBuild {
cmake { cmake {
path "../src/CMakeLists.txt" path "../src/CMakeLists.txt"
// The default CMake version for the Android Gradle Plugin is 3.10.2. // The default CMake version for the Android Gradle Plugin is 3.10.2.
// https://developer.android.com/studio/projects/install-ndk#vanilla_cmake // https://developer.android.com/studio/projects/install-ndk#vanilla_cmake
// //
// The Flutter tooling requires that developers have CMake 3.10 or later // The Flutter tooling requires that developers have CMake 3.10 or later
// installed. You should not increase this version, as doing so will cause // installed. You should not increase this version, as doing so will cause
// the plugin to fail to compile for some customers of the plugin. // the plugin to fail to compile for some customers of the plugin.
// version "3.10.2" // version "3.10.2"
} }
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
defaultConfig { defaultConfig {
minSdkVersion 21 minSdkVersion 21
} }
} }

View File

@ -1 +1 @@
rootProject.name = 'deezcryptor' rootProject.name = 'deezcryptor'

View File

@ -1,3 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.deezcryptor"> package="com.example.deezcryptor">
</manifest> </manifest>

View File

@ -1,19 +1,19 @@
# Run with `flutter pub run ffigen --config ffigen.yaml`. # Run with `flutter pub run ffigen --config ffigen.yaml`.
name: DeezcryptorBindings name: DeezcryptorBindings
description: | description: |
Bindings for `src/deezcryptor.h`. Bindings for `src/deezcryptor.h`.
Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`. Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`.
output: 'lib/deezcryptor_bindings_generated.dart' output: 'lib/deezcryptor_bindings_generated.dart'
headers: headers:
entry-points: entry-points:
- 'src/deezcryptor.h' - 'src/deezcryptor.h'
include-directives: include-directives:
- 'src/deezcryptor.h' - 'src/deezcryptor.h'
preamble: | preamble: |
// ignore_for_file: always_specify_types // ignore_for_file: always_specify_types
// ignore_for_file: camel_case_types // ignore_for_file: camel_case_types
// ignore_for_file: non_constant_identifier_names // ignore_for_file: non_constant_identifier_names
comments: comments:
style: any style: any
length: full length: full

View File

@ -1,3 +1,3 @@
// Relative import to be able to reuse the C sources. // Relative import to be able to reuse the C sources.
// See the comment in ../{projectName}}.podspec for more information. // See the comment in ../{projectName}}.podspec for more information.
#include "../../src/deezcryptor.c" #include "../../src/deezcryptor.c"

View File

@ -1,28 +1,28 @@
# #
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint deezcryptor.podspec` to validate before publishing. # Run `pod lib lint deezcryptor.podspec` to validate before publishing.
# #
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'deezcryptor' s.name = 'deezcryptor'
s.version = '0.0.1' s.version = '0.0.1'
s.summary = 'A new Flutter FFI plugin project.' s.summary = 'A new Flutter FFI plugin project.'
s.description = <<-DESC s.description = <<-DESC
A new Flutter FFI plugin project. A new Flutter FFI plugin project.
DESC DESC
s.homepage = 'http://example.com' s.homepage = 'http://example.com'
s.license = { :file => '../LICENSE' } s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'email@example.com' } s.author = { 'Your Company' => 'email@example.com' }
# This will ensure the source files in Classes/ are included in the native # This will ensure the source files in Classes/ are included in the native
# builds of apps using this FFI plugin. Podspec does not support relative # builds of apps using this FFI plugin. Podspec does not support relative
# paths, so Classes contains a forwarder C file that relatively imports # paths, so Classes contains a forwarder C file that relatively imports
# `../src/*` so that the C sources can be shared among all target platforms. # `../src/*` so that the C sources can be shared among all target platforms.
s.source = { :path => '.' } s.source = { :path => '.' }
s.source_files = 'Classes/**/*' s.source_files = 'Classes/**/*'
s.dependency 'Flutter' s.dependency 'Flutter'
s.platform = :ios, '11.0' s.platform = :ios, '11.0'
# Flutter.framework does not contain a i386 slice. # Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
s.swift_version = '5.0' s.swift_version = '5.0'
end end

View File

@ -1,55 +1,55 @@
import 'dart:ffi' as ffi; import 'dart:ffi' as ffi;
import 'dart:io'; import 'dart:io';
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
import 'deezcryptor_bindings_generated.dart'; import 'deezcryptor_bindings_generated.dart';
const String _libName = 'deezcryptor'; const String _libName = 'deezcryptor';
/// The dynamic library in which the symbols for [DeezcryptorBindings] can be found. /// The dynamic library in which the symbols for [DeezcryptorBindings] can be found.
final ffi.DynamicLibrary _dylib = () { final ffi.DynamicLibrary _dylib = () {
if (Platform.isMacOS || Platform.isIOS) { if (Platform.isMacOS || Platform.isIOS) {
return ffi.DynamicLibrary.open('$_libName.framework/$_libName'); return ffi.DynamicLibrary.open('$_libName.framework/$_libName');
} }
if (Platform.isAndroid || Platform.isLinux) { if (Platform.isAndroid || Platform.isLinux) {
return ffi.DynamicLibrary.open('lib$_libName.so'); return ffi.DynamicLibrary.open('lib$_libName.so');
} }
if (Platform.isWindows) { if (Platform.isWindows) {
return ffi.DynamicLibrary.open('$_libName.dll'); return ffi.DynamicLibrary.open('$_libName.dll');
} }
throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}'); throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
}(); }();
/// The bindings to the native functions in [_dylib]. /// The bindings to the native functions in [_dylib].
final DeezcryptorBindings _bindings = DeezcryptorBindings(_dylib); final DeezcryptorBindings _bindings = DeezcryptorBindings(_dylib);
final decryptChunkRaw = _bindings.decryptChunk; final decryptChunkRaw = _bindings.decryptChunk;
List<int> decryptChunk(List<int> data, List<int> key) { List<int> decryptChunk(List<int> data, List<int> key) {
final ptr = malloc<ffi.Char>(data.length); final ptr = malloc<ffi.Char>(data.length);
final ptr1 = listIntToPointerChar(data); final ptr1 = listIntToPointerChar(data);
final ptr2 = listIntToPointerChar(key); final ptr2 = listIntToPointerChar(key);
final size = _bindings.decryptChunk(ptr, ptr1, ptr2); final size = _bindings.decryptChunk(ptr, ptr1, ptr2);
malloc.free(ptr1); malloc.free(ptr1);
malloc.free(ptr2); malloc.free(ptr2);
final dec = pointerCharToListInt(ptr, size); final dec = pointerCharToListInt(ptr, size);
malloc.free(ptr); malloc.free(ptr);
return dec; return dec;
} }
ffi.Pointer<ffi.Char> listIntToPointerChar<T>(List<int> list) { ffi.Pointer<ffi.Char> listIntToPointerChar<T>(List<int> list) {
final length = list.length; final length = list.length;
final ptr = malloc<ffi.Char>(length); final ptr = malloc<ffi.Char>(length);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
ptr[i] = list[i]; ptr[i] = list[i];
} }
return ptr; return ptr;
} }
List<int> pointerCharToListInt(ffi.Pointer<ffi.Char> ptr, int size) { List<int> pointerCharToListInt(ffi.Pointer<ffi.Char> ptr, int size) {
return List<int>.unmodifiable( return List<int>.unmodifiable(
Iterable<int>.generate(size, (index) => ptr[index])); Iterable<int>.generate(size, (index) => ptr[index]));
} }

View File

@ -1,48 +1,48 @@
// ignore_for_file: always_specify_types // ignore_for_file: always_specify_types
// ignore_for_file: camel_case_types // ignore_for_file: camel_case_types
// ignore_for_file: non_constant_identifier_names // ignore_for_file: non_constant_identifier_names
// AUTO GENERATED FILE, DO NOT EDIT. // AUTO GENERATED FILE, DO NOT EDIT.
// //
// Generated by `package:ffigen`. // Generated by `package:ffigen`.
import 'dart:ffi' as ffi; import 'dart:ffi' as ffi;
/// Bindings for `src/deezcryptor.h`. /// Bindings for `src/deezcryptor.h`.
/// ///
/// Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`. /// Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`.
/// ///
class DeezcryptorBindings { class DeezcryptorBindings {
/// Holds the symbol lookup function. /// Holds the symbol lookup function.
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName) final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
_lookup; _lookup;
/// The symbols are looked up in [dynamicLibrary]. /// The symbols are looked up in [dynamicLibrary].
DeezcryptorBindings(ffi.DynamicLibrary dynamicLibrary) DeezcryptorBindings(ffi.DynamicLibrary dynamicLibrary)
: _lookup = dynamicLibrary.lookup; : _lookup = dynamicLibrary.lookup;
/// The symbols are looked up with [lookup]. /// The symbols are looked up with [lookup].
DeezcryptorBindings.fromLookup( DeezcryptorBindings.fromLookup(
ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName) ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
lookup) lookup)
: _lookup = lookup; : _lookup = lookup;
int decryptChunk( int decryptChunk(
ffi.Pointer<ffi.Char> buffer, ffi.Pointer<ffi.Char> buffer,
ffi.Pointer<ffi.Char> encrypted, ffi.Pointer<ffi.Char> encrypted,
ffi.Pointer<ffi.Char> key, ffi.Pointer<ffi.Char> key,
) { ) {
return _decryptChunk( return _decryptChunk(
buffer, buffer,
encrypted, encrypted,
key, key,
); );
} }
late final _decryptChunkPtr = _lookup< late final _decryptChunkPtr = _lookup<
ffi.NativeFunction< ffi.NativeFunction<
ffi.Int Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>, ffi.Int Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>)>>('decryptChunk'); ffi.Pointer<ffi.Char>)>>('decryptChunk');
late final _decryptChunk = _decryptChunkPtr.asFunction< late final _decryptChunk = _decryptChunkPtr.asFunction<
int Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>, int Function(ffi.Pointer<ffi.Char>, ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>)>(); ffi.Pointer<ffi.Char>)>();
} }

View File

@ -1,22 +1,22 @@
# The Flutter tooling requires that developers have CMake 3.10 or later # The Flutter tooling requires that developers have CMake 3.10 or later
# installed. You should not increase this version, as doing so will cause # installed. You should not increase this version, as doing so will cause
# the plugin to fail to compile for some customers of the plugin. # the plugin to fail to compile for some customers of the plugin.
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
# Project-level configuration. # Project-level configuration.
set(PROJECT_NAME "deezcryptor") set(PROJECT_NAME "deezcryptor")
project(${PROJECT_NAME} LANGUAGES CXX) project(${PROJECT_NAME} LANGUAGES CXX)
# Invoke the build for native code shared with the other target platforms. # Invoke the build for native code shared with the other target platforms.
# This can be changed to accommodate different builds. # This can be changed to accommodate different builds.
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared") add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared")
# List of absolute paths to libraries that should be bundled with the plugin. # List of absolute paths to libraries that should be bundled with the plugin.
# This list could contain prebuilt libraries, or libraries created by an # This list could contain prebuilt libraries, or libraries created by an
# external build triggered from this build file. # external build triggered from this build file.
set(deezcryptor_bundled_libraries set(deezcryptor_bundled_libraries
# Defined in ../src/CMakeLists.txt. # Defined in ../src/CMakeLists.txt.
# This can be changed to accommodate different builds. # This can be changed to accommodate different builds.
$<TARGET_FILE:deezcryptor> $<TARGET_FILE:deezcryptor>
PARENT_SCOPE PARENT_SCOPE
) )

View File

@ -1,3 +1,3 @@
// Relative import to be able to reuse the C sources. // Relative import to be able to reuse the C sources.
// See the comment in ../{projectName}}.podspec for more information. // See the comment in ../{projectName}}.podspec for more information.
#include "../../src/deezcryptor.c" #include "../../src/deezcryptor.c"

View File

@ -1,27 +1,27 @@
# #
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint deezcryptor.podspec` to validate before publishing. # Run `pod lib lint deezcryptor.podspec` to validate before publishing.
# #
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'deezcryptor' s.name = 'deezcryptor'
s.version = '0.0.1' s.version = '0.0.1'
s.summary = 'A new Flutter FFI plugin project.' s.summary = 'A new Flutter FFI plugin project.'
s.description = <<-DESC s.description = <<-DESC
A new Flutter FFI plugin project. A new Flutter FFI plugin project.
DESC DESC
s.homepage = 'http://example.com' s.homepage = 'http://example.com'
s.license = { :file => '../LICENSE' } s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'email@example.com' } s.author = { 'Your Company' => 'email@example.com' }
# This will ensure the source files in Classes/ are included in the native # This will ensure the source files in Classes/ are included in the native
# builds of apps using this FFI plugin. Podspec does not support relative # builds of apps using this FFI plugin. Podspec does not support relative
# paths, so Classes contains a forwarder C file that relatively imports # paths, so Classes contains a forwarder C file that relatively imports
# `../src/*` so that the C sources can be shared among all target platforms. # `../src/*` so that the C sources can be shared among all target platforms.
s.source = { :path => '.' } s.source = { :path => '.' }
s.source_files = 'Classes/**/*' s.source_files = 'Classes/**/*'
s.dependency 'FlutterMacOS' s.dependency 'FlutterMacOS'
s.platform = :osx, '10.11' s.platform = :osx, '10.11'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
s.swift_version = '5.0' s.swift_version = '5.0'
end end

View File

@ -1,35 +1,35 @@
name: deezcryptor name: deezcryptor
description: A deezer decryptor written in C description: A deezer decryptor written in C
version: 0.0.1 version: 0.0.1
homepage: homepage:
environment: environment:
sdk: '>=3.0.6 <4.0.0' sdk: '>=3.0.6 <4.0.0'
flutter: ">=3.3.0" flutter: ">=3.3.0"
dependencies: dependencies:
ffi: ^2.0.2 ffi: ^2.0.2
flutter: flutter:
sdk: flutter sdk: flutter
plugin_platform_interface: ^2.0.2 plugin_platform_interface: ^2.0.2
dev_dependencies: dev_dependencies:
ffigen: ^6.1.2 ffigen: ^6.1.2
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^2.0.0 flutter_lints: ^2.0.0
flutter: flutter:
plugin: plugin:
platforms: platforms:
android: android:
ffiPlugin: true ffiPlugin: true
ios: ios:
ffiPlugin: true ffiPlugin: true
linux: linux:
ffiPlugin: true ffiPlugin: true
macos: macos:
ffiPlugin: true ffiPlugin: true
windows: windows:
ffiPlugin: true ffiPlugin: true

View File

@ -1,33 +1,33 @@
# The Flutter tooling requires that developers have CMake 3.10 or later # The Flutter tooling requires that developers have CMake 3.10 or later
# installed. You should not increase this version, as doing so will cause # installed. You should not increase this version, as doing so will cause
# the plugin to fail to compile for some customers of the plugin. # the plugin to fail to compile for some customers of the plugin.
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
project(deezcryptor VERSION 0.0.1 LANGUAGES C) project(deezcryptor VERSION 0.0.1 LANGUAGES C)
SET(OPENSSL_ROOT_DIR openssl) SET(OPENSSL_ROOT_DIR openssl)
SET(OPENSSL_LIBRARIES_DIR "lib/${ANDROID_ABI}") SET(OPENSSL_LIBRARIES_DIR "lib/${ANDROID_ABI}")
SET(OPENSSL_INCLUDE_DIR ${OPENSSL_ROOT_DIR}/include) SET(OPENSSL_INCLUDE_DIR ${OPENSSL_ROOT_DIR}/include)
SET(OPENSSL_LIBRARIES "ssl" "crypto") SET(OPENSSL_LIBRARIES "ssl" "crypto")
set(OPENSSL_USE_STATIC_LIBS TRUE) set(OPENSSL_USE_STATIC_LIBS TRUE)
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
target_link_libraries(deezcryptor OpenSSL::Crypto) target_link_libraries(deezcryptor OpenSSL::Crypto)
LINK_DIRECTORIES(${OPENSSL_LIBRARIES_DIR}) LINK_DIRECTORIES(${OPENSSL_LIBRARIES_DIR})
add_library(deezcryptor SHARED add_library(deezcryptor SHARED
"deezcryptor.c" "deezcryptor.c"
) )
set_target_properties(deezcryptor PROPERTIES set_target_properties(deezcryptor PROPERTIES
PUBLIC_HEADER deezcryptor.h PUBLIC_HEADER deezcryptor.h
OUTPUT_NAME "deezcryptor" OUTPUT_NAME "deezcryptor"
) )
TARGET_INCLUDE_DIRECTORIES(deezcryptor PUBLIC ${OPENSSL_INCLUDE_DIR}) TARGET_INCLUDE_DIRECTORIES(deezcryptor PUBLIC ${OPENSSL_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(deezcryptor ${OPENSSL_LIBRARIES}) TARGET_LINK_LIBRARIES(deezcryptor ${OPENSSL_LIBRARIES})
target_compile_definitions(deezcryptor PUBLIC DART_SHARED_LIB) target_compile_definitions(deezcryptor PUBLIC DART_SHARED_LIB)

View File

@ -1,14 +1,14 @@
#include "deezcryptor.h" #include "deezcryptor.h"
#include <openssl/blowfish.h> #include <openssl/blowfish.h>
#define CHUNK_SIZE 2048 #define CHUNK_SIZE 2048
FFI_PLUGIN_EXPORT int decryptChunk(unsigned char *buffer, unsigned char *encrypted, unsigned char *key) FFI_PLUGIN_EXPORT int decryptChunk(unsigned char *buffer, unsigned char *encrypted, unsigned char *key)
{ {
BF_KEY _key; BF_KEY _key;
BF_set_key(&_key, 16, key); BF_set_key(&_key, 16, key);
unsigned char IV = {0, 1, 2, 3, 4, 5, 6, 7}; unsigned char IV = {0, 1, 2, 3, 4, 5, 6, 7};
BF_cbc_encrypt(encrypted, buffer, CHUNK_SIZE, &_key, IV, BF_DECRYPT); BF_cbc_encrypt(encrypted, buffer, CHUNK_SIZE, &_key, IV, BF_DECRYPT);
return CHUNK_SIZE; return CHUNK_SIZE;
} }

View File

@ -1,7 +1,7 @@
#if _WIN32 #if _WIN32
#define FFI_PLUGIN_EXPORT __declspec(dllexport) #define FFI_PLUGIN_EXPORT __declspec(dllexport)
#else #else
#define FFI_PLUGIN_EXPORT #define FFI_PLUGIN_EXPORT
#endif #endif
FFI_PLUGIN_EXPORT int decryptChunk(char *buffer, char *encrypted, char *key); FFI_PLUGIN_EXPORT int decryptChunk(char *buffer, char *encrypted, char *key);

View File

@ -1,17 +1,17 @@
flutter/ flutter/
# Visual Studio user-specific files. # Visual Studio user-specific files.
*.suo *.suo
*.user *.user
*.userosscache *.userosscache
*.sln.docstates *.sln.docstates
# Visual Studio build-related files. # Visual Studio build-related files.
x64/ x64/
x86/ x86/
# Visual Studio cache files # Visual Studio cache files
# files ending in .cache can be ignored # files ending in .cache can be ignored
*.[Cc]ache *.[Cc]ache
# but keep track of directories ending in .cache # but keep track of directories ending in .cache
!*.[Cc]ache/ !*.[Cc]ache/

View File

@ -1,23 +1,23 @@
# The Flutter tooling requires that developers have a version of Visual Studio # The Flutter tooling requires that developers have a version of Visual Studio
# installed that includes CMake 3.14 or later. You should not increase this # installed that includes CMake 3.14 or later. You should not increase this
# version, as doing so will cause the plugin to fail to compile for some # version, as doing so will cause the plugin to fail to compile for some
# customers of the plugin. # customers of the plugin.
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
# Project-level configuration. # Project-level configuration.
set(PROJECT_NAME "deezcryptor") set(PROJECT_NAME "deezcryptor")
project(${PROJECT_NAME} LANGUAGES CXX) project(${PROJECT_NAME} LANGUAGES CXX)
# Invoke the build for native code shared with the other target platforms. # Invoke the build for native code shared with the other target platforms.
# This can be changed to accommodate different builds. # This can be changed to accommodate different builds.
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared") add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared")
# List of absolute paths to libraries that should be bundled with the plugin. # List of absolute paths to libraries that should be bundled with the plugin.
# This list could contain prebuilt libraries, or libraries created by an # This list could contain prebuilt libraries, or libraries created by an
# external build triggered from this build file. # external build triggered from this build file.
set(deezcryptor_bundled_libraries set(deezcryptor_bundled_libraries
# Defined in ../src/CMakeLists.txt. # Defined in ../src/CMakeLists.txt.
# This can be changed to accommodate different builds. # This can be changed to accommodate different builds.
$<TARGET_FILE:deezcryptor> $<TARGET_FILE:deezcryptor>
PARENT_SCOPE PARENT_SCOPE
) )

68
ios/.gitignore vendored
View File

@ -1,34 +1,34 @@
**/dgph **/dgph
*.mode1v3 *.mode1v3
*.mode2v3 *.mode2v3
*.moved-aside *.moved-aside
*.pbxuser *.pbxuser
*.perspectivev3 *.perspectivev3
**/*sync/ **/*sync/
.sconsign.dblite .sconsign.dblite
.tags* .tags*
**/.vagrant/ **/.vagrant/
**/DerivedData/ **/DerivedData/
Icon? Icon?
**/Pods/ **/Pods/
**/.symlinks/ **/.symlinks/
profile profile
xcuserdata xcuserdata
**/.generated/ **/.generated/
Flutter/App.framework Flutter/App.framework
Flutter/Flutter.framework Flutter/Flutter.framework
Flutter/Flutter.podspec Flutter/Flutter.podspec
Flutter/Generated.xcconfig Flutter/Generated.xcconfig
Flutter/ephemeral/ Flutter/ephemeral/
Flutter/app.flx Flutter/app.flx
Flutter/app.zip Flutter/app.zip
Flutter/flutter_assets/ Flutter/flutter_assets/
Flutter/flutter_export_environment.sh Flutter/flutter_export_environment.sh
ServiceDefinitions.json ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.* Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules. # Exceptions to above rules.
!default.mode1v3 !default.mode1v3
!default.mode2v3 !default.mode2v3
!default.pbxuser !default.pbxuser
!default.perspectivev3 !default.perspectivev3

View File

@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>en</string> <string>en</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>App</string> <string>App</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string> <string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>App</string> <string>App</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0</string> <string>1.0</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>11.0</string> <string>11.0</string>
</dict> </dict>
</plist> </plist>

View File

@ -1 +1 @@
#include "Generated.xcconfig" #include "Generated.xcconfig"

View File

@ -1 +1 @@
#include "Generated.xcconfig" #include "Generated.xcconfig"

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Workspace <Workspace
version = "1.0"> version = "1.0">
<FileRef <FileRef
location = "self:"> location = "self:">
</FileRef> </FileRef>
</Workspace> </Workspace>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>IDEDidComputeMac32BitWarning</key> <key>IDEDidComputeMac32BitWarning</key>
<true/> <true/>
</dict> </dict>
</plist> </plist>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>PreviewsEnabled</key> <key>PreviewsEnabled</key>
<false/> <false/>
</dict> </dict>
</plist> </plist>

View File

@ -1,98 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1300" LastUpgradeVersion = "1300"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"> buildImplicitDependencies = "YES">
<BuildActionEntries> <BuildActionEntries>
<BuildActionEntry <BuildActionEntry
buildForTesting = "YES" buildForTesting = "YES"
buildForRunning = "YES" buildForRunning = "YES"
buildForProfiling = "YES" buildForProfiling = "YES"
buildForArchiving = "YES" buildForArchiving = "YES"
buildForAnalyzing = "YES"> buildForAnalyzing = "YES">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D" BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app" BuildableName = "Runner.app"
BlueprintName = "Runner" BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion> <MacroExpansion>
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D" BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app" BuildableName = "Runner.app"
BlueprintName = "Runner" BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<Testables> <Testables>
<TestableReference <TestableReference
skipped = "NO" skipped = "NO"
parallelizable = "YES"> parallelizable = "YES">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5" BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest" BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests" BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
</Testables> </Testables>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D" BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app" BuildableName = "Runner.app"
BlueprintName = "Runner" BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Profile" buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = "" savedToolIdentifier = ""
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"> debugDocumentVersioning = "YES">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D" BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app" BuildableName = "Runner.app"
BlueprintName = "Runner" BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</ProfileAction> </ProfileAction>
<AnalyzeAction <AnalyzeAction
buildConfiguration = "Debug"> buildConfiguration = "Debug">
</AnalyzeAction> </AnalyzeAction>
<ArchiveAction <ArchiveAction
buildConfiguration = "Release" buildConfiguration = "Release"
revealArchiveInOrganizer = "YES"> revealArchiveInOrganizer = "YES">
</ArchiveAction> </ArchiveAction>
</Scheme> </Scheme>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Workspace <Workspace
version = "1.0"> version = "1.0">
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "group:Runner.xcodeproj">
</FileRef> </FileRef>
</Workspace> </Workspace>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>IDEDidComputeMac32BitWarning</key> <key>IDEDidComputeMac32BitWarning</key>
<true/> <true/>
</dict> </dict>
</plist> </plist>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>PreviewsEnabled</key> <key>PreviewsEnabled</key>
<false/> <false/>
</dict> </dict>
</plist> </plist>

View File

@ -1,13 +1,13 @@
import UIKit import UIKit
import Flutter import Flutter
@UIApplicationMain @UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate { @objc class AppDelegate: FlutterAppDelegate {
override func application( override func application(
_ application: UIApplication, _ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
GeneratedPluginRegistrant.register(with: self) GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }
} }

View File

@ -1,122 +1,122 @@
{ {
"images" : [ "images" : [
{ {
"size" : "20x20", "size" : "20x20",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png", "filename" : "Icon-App-20x20@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "20x20", "size" : "20x20",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png", "filename" : "Icon-App-20x20@3x.png",
"scale" : "3x" "scale" : "3x"
}, },
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png", "filename" : "Icon-App-29x29@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png", "filename" : "Icon-App-29x29@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png", "filename" : "Icon-App-29x29@3x.png",
"scale" : "3x" "scale" : "3x"
}, },
{ {
"size" : "40x40", "size" : "40x40",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png", "filename" : "Icon-App-40x40@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "40x40", "size" : "40x40",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png", "filename" : "Icon-App-40x40@3x.png",
"scale" : "3x" "scale" : "3x"
}, },
{ {
"size" : "60x60", "size" : "60x60",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png", "filename" : "Icon-App-60x60@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "60x60", "size" : "60x60",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png", "filename" : "Icon-App-60x60@3x.png",
"scale" : "3x" "scale" : "3x"
}, },
{ {
"size" : "20x20", "size" : "20x20",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png", "filename" : "Icon-App-20x20@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "20x20", "size" : "20x20",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png", "filename" : "Icon-App-20x20@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png", "filename" : "Icon-App-29x29@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png", "filename" : "Icon-App-29x29@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "40x40", "size" : "40x40",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png", "filename" : "Icon-App-40x40@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "40x40", "size" : "40x40",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png", "filename" : "Icon-App-40x40@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "76x76", "size" : "76x76",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png", "filename" : "Icon-App-76x76@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "76x76", "size" : "76x76",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png", "filename" : "Icon-App-76x76@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "83.5x83.5", "size" : "83.5x83.5",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png", "filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "1024x1024", "size" : "1024x1024",
"idiom" : "ios-marketing", "idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png", "filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x" "scale" : "1x"
} }
], ],
"info" : { "info" : {
"version" : 1, "version" : 1,
"author" : "xcode" "author" : "xcode"
} }
} }

View File

@ -1,23 +1,23 @@
{ {
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"filename" : "LaunchImage.png", "filename" : "LaunchImage.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"filename" : "LaunchImage@2x.png", "filename" : "LaunchImage@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"filename" : "LaunchImage@3x.png", "filename" : "LaunchImage@3x.png",
"scale" : "3x" "scale" : "3x"
} }
], ],
"info" : { "info" : {
"version" : 1, "version" : 1,
"author" : "xcode" "author" : "xcode"
} }
} }

View File

@ -1,5 +1,5 @@
# Launch Screen Assets # Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory. You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.

View File

@ -1,37 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies> </dependencies>
<scenes> <scenes>
<!--View Controller--> <!--View Controller-->
<scene sceneID="EHf-IW-A2E"> <scene sceneID="EHf-IW-A2E">
<objects> <objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController"> <viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides> <layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/> <viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/> <viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides> </layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"> <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView> </imageView>
</subviews> </subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/> <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/> <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints> </constraints>
</view> </view>
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="53" y="375"/> <point key="canvasLocation" x="53" y="375"/>
</scene> </scene>
</scenes> </scenes>
<resources> <resources>
<image name="LaunchImage" width="168" height="185"/> <image name="LaunchImage" width="168" height="185"/>
</resources> </resources>
</document> </document>

View File

@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies> </dependencies>
<scenes> <scenes>
<!--Flutter View Controller--> <!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu"> <scene sceneID="tne-QT-ifu">
<objects> <objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController"> <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides> <layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/> <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides> </layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view> </view>
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects> </objects>
</scene> </scene>
</scenes> </scenes>
</document> </document>

View File

@ -1,51 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>Freezer</string> <string>Freezer</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>freezer</string> <string>freezer</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string> <string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>
<string>Main</string> <string>Main</string>
<key>UISupportedInterfaceOrientations</key> <key>UISupportedInterfaceOrientations</key>
<array> <array>
<string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>UISupportedInterfaceOrientations~ipad</key> <key>UISupportedInterfaceOrientations~ipad</key>
<array> <array>
<string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string> <string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>CADisableMinimumFrameDurationOnPhone</key> <key>CADisableMinimumFrameDurationOnPhone</key>
<true/> <true/>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
</dict> </dict>
</plist> </plist>

View File

@ -1 +1 @@
#import "GeneratedPluginRegistrant.h" #import "GeneratedPluginRegistrant.h"

View File

@ -1,12 +1,12 @@
import Flutter import Flutter
import UIKit import UIKit
import XCTest import XCTest
class RunnerTests: XCTestCase { class RunnerTests: XCTestCase {
func testExample() { func testExample() {
// If you add code to the Runner application, consider adding tests here. // If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest. // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
} }
} }

View File

@ -1,104 +1,104 @@
// ignore_for_file: implementation_imports // ignore_for_file: implementation_imports
import 'package:dart_blowfish/dart_blowfish.dart'; import 'package:dart_blowfish/dart_blowfish.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_cache_manager/src/storage/cache_object.dart'; import 'package:flutter_cache_manager/src/storage/cache_object.dart';
import 'package:freezer/type_adapters/uri.dart'; import 'package:freezer/type_adapters/uri.dart';
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
class FreezerCacheManager extends CacheManager { class FreezerCacheManager extends CacheManager {
static const key = 'freezerImageCache'; static const key = 'freezerImageCache';
void init(String path, {String? boxName}) { void init(String path, {String? boxName}) {
_instance = _instance =
FreezerCacheManager._(FreezerCacheInfoRepository(boxName ?? key, path)); FreezerCacheManager._(FreezerCacheInfoRepository(boxName ?? key, path));
} }
static late final FreezerCacheManager _instance; static late final FreezerCacheManager _instance;
factory FreezerCacheManager() => _instance; factory FreezerCacheManager() => _instance;
FreezerCacheManager._(FreezerCacheInfoRepository repo) FreezerCacheManager._(FreezerCacheInfoRepository repo)
: super(Config(key, repo: repo)); : super(Config(key, repo: repo));
} }
class FreezerCacheInfoRepository extends CacheInfoRepository { class FreezerCacheInfoRepository extends CacheInfoRepository {
final String boxName; final String boxName;
final String path; final String path;
late final LazyBox<CacheObject> _box; late final LazyBox<CacheObject> _box;
bool _isOpen; bool _isOpen;
FreezerCacheInfoRepository(this.boxName, this.path); FreezerCacheInfoRepository(this.boxName, this.path);
@override @override
Future<bool> exists() => Hive.boxExists(boxName, path: path); Future<bool> exists() => Hive.boxExists(boxName, path: path);
@override @override
Future<bool> open() async { Future<bool> open() async {
if (_isOpen) return true; if (_isOpen) return true;
_box = await Hive.openLazyBox<CacheObject>(boxName, path: path); _box = await Hive.openLazyBox<CacheObject>(boxName, path: path);
_isOpen = true; _isOpen = true;
return true; return true;
} }
@override @override
Future<dynamic> updateOrInsert(CacheObject cacheObject) { Future<dynamic> updateOrInsert(CacheObject cacheObject) {
if (cacheObject.id == null) { if (cacheObject.id == null) {
return insert(cacheObject); return insert(cacheObject);
} else { } else {
return update(cacheObject); return update(cacheObject);
} }
} }
@override @override
Future<CacheObject> insert(CacheObject cacheObject, Future<CacheObject> insert(CacheObject cacheObject,
{bool setTouchedToNow = true}) { {bool setTouchedToNow = true}) {
final id = await _box.add(cacheObject); final id = await _box.add(cacheObject);
} }
/// Gets a [CacheObject] by [key] /// Gets a [CacheObject] by [key]
@override @override
Future<CacheObject?> get(String key); Future<CacheObject?> get(String key);
/// Deletes a cache object by [id] /// Deletes a cache object by [id]
@override @override
Future<int> delete(int id); Future<int> delete(int id);
/// Deletes items with [ids] from the repository /// Deletes items with [ids] from the repository
@override @override
Future<int> deleteAll(Iterable<int> ids); Future<int> deleteAll(Iterable<int> ids);
/// Updates an existing [cacheObject] /// Updates an existing [cacheObject]
@override @override
Future<int> update(CacheObject cacheObject, {bool setTouchedToNow = true}); Future<int> update(CacheObject cacheObject, {bool setTouchedToNow = true});
/// Gets the list of all objects in the cache /// Gets the list of all objects in the cache
@override @override
Future<List<CacheObject>> getAllObjects(); Future<List<CacheObject>> getAllObjects();
/// Gets the list of [CacheObject] that can be removed if the repository is over capacity. /// Gets the list of [CacheObject] that can be removed if the repository is over capacity.
/// ///
/// The exact implementation is up to the repository, but implementations should /// The exact implementation is up to the repository, but implementations should
/// return a preferred list of items. For example, the least recently accessed /// return a preferred list of items. For example, the least recently accessed
@override @override
Future<List<CacheObject>> getObjectsOverCapacity(int capacity); Future<List<CacheObject>> getObjectsOverCapacity(int capacity);
/// Returns a list of [CacheObject] that are older than [maxAge] /// Returns a list of [CacheObject] that are older than [maxAge]
@override @override
Future<List<CacheObject>> getOldObjects(Duration maxAge); Future<List<CacheObject>> getOldObjects(Duration maxAge);
/// Close the connection to the repository. If this is the last connection /// Close the connection to the repository. If this is the last connection
/// to the repository it will return true and the repository is truly /// to the repository it will return true and the repository is truly
/// closed. If there are still open connections it will return false; /// closed. If there are still open connections it will return false;
@override @override
Future<bool> close(); Future<bool> close();
/// Deletes the cache data file including all cache data. /// Deletes the cache data file including all cache data.
@override @override
Future<void> deleteDataFile(); Future<void> deleteDataFile();
} }
class CacheObjectAdapter extends TypeAdapter<CacheObject> { class CacheObjectAdapter extends TypeAdapter<CacheObject> {
@override @override
// TODO: implement typeId // TODO: implement typeId
int get typeId => throw UnimplementedError(); int get typeId => throw UnimplementedError();
} }

View File

@ -1,394 +1,394 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:encrypt/encrypt.dart'; import 'package:encrypt/encrypt.dart';
import 'package:flutter/foundation.dart' as flutter; import 'package:flutter/foundation.dart' as flutter;
import 'package:freezer/api/deezer.dart'; import 'package:freezer/api/deezer.dart';
import 'package:freezer/api/definitions.dart'; import 'package:freezer/api/definitions.dart';
import 'package:freezer/settings.dart'; import 'package:freezer/settings.dart';
import 'package:just_audio/just_audio.dart'; import 'package:just_audio/just_audio.dart';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:dart_blowfish/dart_blowfish.dart'; import 'package:dart_blowfish/dart_blowfish.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:scrobblenaut/lastfm.dart'; import 'package:scrobblenaut/lastfm.dart';
typedef _IsolateMessage = ( typedef _IsolateMessage = (
Stream<List<int>> source, Stream<List<int>> source,
int start, int start,
String trackId, String trackId,
SendPort sendPort SendPort sendPort
); );
// Maybe better implementation of Blowfish CBC instead of random-ass, unpublished library from github? // Maybe better implementation of Blowfish CBC instead of random-ass, unpublished library from github?
// This class can be considered a rewrite in Dart of the Java backend (from the StreamServer.deezer() function and also from the Deezer class) // This class can be considered a rewrite in Dart of the Java backend (from the StreamServer.deezer() function and also from the Deezer class)
class DeezerAudioSource extends StreamAudioSource { class DeezerAudioSource extends StreamAudioSource {
final _logger = Logger("DeezerAudioSource"); final _logger = Logger("DeezerAudioSource");
late AudioQuality Function() _getQuality; late AudioQuality Function() _getQuality;
late AudioQuality? _initialQuality; late AudioQuality? _initialQuality;
late String _trackId; late String _trackId;
late String _md5origin; late String _md5origin;
late String _mediaVersion; late String _mediaVersion;
final String trackToken; final String trackToken;
final int trackTokenExpiration; final int trackTokenExpiration;
final StreamInfoCallback? onStreamObtained; final StreamInfoCallback? onStreamObtained;
// some cache // some cache
AudioQuality? _currentQuality; AudioQuality? _currentQuality;
int? _cachedSourceLength; int? _cachedSourceLength;
String? _cachedContentType; String? _cachedContentType;
Uri? _downloadUrl; Uri? _downloadUrl;
DeezerAudioSource({ DeezerAudioSource({
required AudioQuality Function() getQuality, required AudioQuality Function() getQuality,
required String trackId, required String trackId,
required String md5origin, required String md5origin,
required String mediaVersion, required String mediaVersion,
required this.trackToken, required this.trackToken,
required this.trackTokenExpiration, required this.trackTokenExpiration,
this.onStreamObtained, this.onStreamObtained,
}) { }) {
_getQuality = getQuality; _getQuality = getQuality;
_initialQuality = quality; _initialQuality = quality;
_trackId = trackId; _trackId = trackId;
_md5origin = md5origin; _md5origin = md5origin;
_mediaVersion = mediaVersion; _mediaVersion = mediaVersion;
} }
AudioQuality? get quality => _currentQuality; AudioQuality? get quality => _currentQuality;
String get trackId => _trackId; String get trackId => _trackId;
String get md5origin => _md5origin; String get md5origin => _md5origin;
String get mediaVersion => _mediaVersion; String get mediaVersion => _mediaVersion;
static const chunkSize = 2048; static const chunkSize = 2048;
void _updateTrackData(Map trackData) { void _updateTrackData(Map trackData) {
_trackId = trackData["SNG_ID"]; _trackId = trackData["SNG_ID"];
_md5origin = trackData["MD5_ORIGIN"]; _md5origin = trackData["MD5_ORIGIN"];
_mediaVersion = trackData["MEDIA_VERSION"]; _mediaVersion = trackData["MEDIA_VERSION"];
} }
Future<Uri> _fallbackUrl() async { Future<Uri> _fallbackUrl() async {
_logger.finer("called _fallbackUrl()"); _logger.finer("called _fallbackUrl()");
try { try {
return await _qualityFallback(); return await _qualityFallback();
} on QualityException { } on QualityException {
_logger.warning("quality fallback failed! trying trackId fallback"); _logger.warning("quality fallback failed! trying trackId fallback");
_currentQuality = _initialQuality; _currentQuality = _initialQuality;
} }
Map? privateJson; Map? privateJson;
try { try {
// TRACK ID FALLBACK // TRACK ID FALLBACK
final data = await deezerAPI final data = await deezerAPI
.callApi("deezer.pageTrack", params: {"sng_id": trackId}); .callApi("deezer.pageTrack", params: {"sng_id": trackId});
privateJson = data["results"]["DATA"]; privateJson = data["results"]["DATA"];
if (privateJson!.containsKey("FALLBACK")) { if (privateJson!.containsKey("FALLBACK")) {
String fallbackId = privateJson["FALLBACK"]["SNG_ID"]; String fallbackId = privateJson["FALLBACK"]["SNG_ID"];
if (fallbackId != trackId) { if (fallbackId != trackId) {
final newPrivate = final newPrivate =
await deezerAPI.callApi("song.getListData", params: { await deezerAPI.callApi("song.getListData", params: {
"sng_ids": [fallbackId] "sng_ids": [fallbackId]
}); });
final Map trackData = newPrivate["results"]["data"][0]; final Map trackData = newPrivate["results"]["data"][0];
_updateTrackData(trackData); _updateTrackData(trackData);
return await _fallbackUrl(); return await _fallbackUrl();
} }
} }
} catch (e, st) { } catch (e, st) {
_logger.warning("ID fallback failed! Trying ISRC fallback!", e, st); _logger.warning("ID fallback failed! Trying ISRC fallback!", e, st);
} }
try { try {
final data = final data =
await deezerAPI.callPublicApi("track/isrc:${privateJson!["ISRC"]!}"); await deezerAPI.callPublicApi("track/isrc:${privateJson!["ISRC"]!}");
final newId = data["id"] as int; final newId = data["id"] as int;
if (newId == int.parse(trackId)) throw Exception(); if (newId == int.parse(trackId)) throw Exception();
final newPrivate = await deezerAPI.callApi("song.getListData", params: { final newPrivate = await deezerAPI.callApi("song.getListData", params: {
"sng_ids": [newId] "sng_ids": [newId]
}); });
final trackData = newPrivate["results"]["data"][0] as Map; final trackData = newPrivate["results"]["data"][0] as Map;
_updateTrackData(trackData); _updateTrackData(trackData);
return await _fallbackUrl(); return await _fallbackUrl();
} catch (e, st) { } catch (e, st) {
_logger.severe("ISRC Fallback failed, track unavailable!", e, st); _logger.severe("ISRC Fallback failed, track unavailable!", e, st);
} }
throw Exception( throw Exception(
"Every known method of fallback failed, track unavailable!"); "Every known method of fallback failed, track unavailable!");
} }
Future<Uri> _qualityFallback() async { Future<Uri> _qualityFallback() async {
// only use url generation with MP3_128 // only use url generation with MP3_128
_currentQuality = AudioQuality.MP3_128; _currentQuality = AudioQuality.MP3_128;
final genUri = _generateTrackUri(); final genUri = _generateTrackUri();
final req = await http.head(genUri, headers: { final req = await http.head(genUri, headers: {
'User-Agent': deezerAPI.headers['User-Agent']!, 'User-Agent': deezerAPI.headers['User-Agent']!,
'Accept-Language': '*', 'Accept-Language': '*',
'Accept': '*/*' 'Accept': '*/*'
}); });
int rc = req.statusCode; int rc = req.statusCode;
if (rc > 400) { if (rc > 400) {
_logger.warning( _logger.warning(
"quality fallback, response code: $rc, current quality: $quality"); "quality fallback, response code: $rc, current quality: $quality");
switch (_currentQuality) { switch (_currentQuality) {
case AudioQuality.FLAC: case AudioQuality.FLAC:
_currentQuality = AudioQuality.MP3_320; _currentQuality = AudioQuality.MP3_320;
break; break;
case AudioQuality.MP3_320: case AudioQuality.MP3_320:
_currentQuality = AudioQuality.MP3_128; _currentQuality = AudioQuality.MP3_128;
break; break;
case AudioQuality.MP3_128: case AudioQuality.MP3_128:
default: default:
_currentQuality = null; _currentQuality = null;
throw QualityException("No quality to fallback to!"); throw QualityException("No quality to fallback to!");
} }
return await _qualityFallback(); return await _qualityFallback();
} }
return genUri; return genUri;
} }
Uri _generateTrackUri() { Uri _generateTrackUri() {
int magic = 164; int magic = 164;
// step 1 // step 1
final step1 = <int>[ final step1 = <int>[
...md5origin.codeUnits, ...md5origin.codeUnits,
magic, magic,
...quality!.toDeezerQualityInt().toString().codeUnits, ...quality!.toDeezerQualityInt().toString().codeUnits,
magic, magic,
...trackId.codeUnits, ...trackId.codeUnits,
magic, magic,
...mediaVersion.codeUnits, ...mediaVersion.codeUnits,
]; ];
// get md5 hash of step1 // get md5 hash of step1
final md5hex = md5.convert(step1).toString().toLowerCase(); final md5hex = md5.convert(step1).toString().toLowerCase();
// step2 // step2
final step2 = <int>[ final step2 = <int>[
...md5hex.codeUnits, ...md5hex.codeUnits,
magic, magic,
...step1, ...step1,
magic, magic,
]; ];
// pad step2 with dots to get correct length // pad step2 with dots to get correct length
while (step2.length % 16 > 0) { while (step2.length % 16 > 0) {
// step2.addAll(('.' * (step2.length % 16)).codeUnits); // step2.addAll(('.' * (step2.length % 16)).codeUnits);
step2.add(46); step2.add(46);
} }
// encrypt with AES ECB // encrypt with AES ECB
final k = Uint8List.fromList('jo6aey6haid2Teih'.codeUnits); final k = Uint8List.fromList('jo6aey6haid2Teih'.codeUnits);
final encrypter = Encrypter(AES(Key(k), mode: AESMode.ecb, padding: null)); final encrypter = Encrypter(AES(Key(k), mode: AESMode.ecb, padding: null));
final String step3 = encrypter final String step3 = encrypter
.encryptBytes(step2, iv: IV(Uint8List(8))) .encryptBytes(step2, iv: IV(Uint8List(8)))
.base16 .base16
.toLowerCase(); .toLowerCase();
final uri = final uri =
Uri.https('e-cdns-proxy-${md5origin[0]}.dzcdn.net', '/mobile/1/$step3'); Uri.https('e-cdns-proxy-${md5origin[0]}.dzcdn.net', '/mobile/1/$step3');
return uri; return uri;
} }
static List<int> getKey(String id) { static List<int> getKey(String id) {
final secret = utf8.encode('g4el58wc0zvf9na1'); final secret = utf8.encode('g4el58wc0zvf9na1');
final idmd5 = final idmd5 =
utf8.encode(md5.convert(utf8.encode(id)).toString().toLowerCase()); utf8.encode(md5.convert(utf8.encode(id)).toString().toLowerCase());
final buffer = <int>[]; final buffer = <int>[];
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
final s0 = idmd5[i]; final s0 = idmd5[i];
final s1 = idmd5[i + 16]; final s1 = idmd5[i + 16];
final s2 = secret[i]; final s2 = secret[i];
buffer.add(s0 ^ s1 ^ s2); buffer.add(s0 ^ s1 ^ s2);
} }
return buffer; return buffer;
} }
static List<int> decryptChunk(List<int> key, List<int> data) { static List<int> decryptChunk(List<int> key, List<int> data) {
final Uint8List iv = final Uint8List iv =
Uint8List.fromList(const [00, 01, 02, 03, 04, 05, 06, 07]); Uint8List.fromList(const [00, 01, 02, 03, 04, 05, 06, 07]);
final bf = Blowfish( final bf = Blowfish(
key: Uint8List.fromList(key), mode: Mode.cbc, padding: Padding.none) key: Uint8List.fromList(key), mode: Mode.cbc, padding: Padding.none)
..setIv(iv); ..setIv(iv);
Uint8List decrypted = bf.decode(data, returnType: Type.uInt8Array); Uint8List decrypted = bf.decode(data, returnType: Type.uInt8Array);
return decrypted; return decrypted;
} }
static Stream<List<int>> decryptionStream(Stream<List<int>> source, static Stream<List<int>> decryptionStream(Stream<List<int>> source,
{required int start, required String trackId}) async* { {required int start, required String trackId}) async* {
var dropBytes = start % 2048; var dropBytes = start % 2048;
final deezerStart = start - dropBytes; final deezerStart = start - dropBytes;
int counter = deezerStart ~/ chunkSize; int counter = deezerStart ~/ chunkSize;
final buffer = List<int>.empty(growable: true); final buffer = List<int>.empty(growable: true);
final key = getKey(trackId); final key = getKey(trackId);
await for (var bytes in source) { await for (var bytes in source) {
buffer.addAll(bytes); buffer.addAll(bytes);
int i; int i;
for (i = 0; i < buffer.length; i += chunkSize) { for (i = 0; i < buffer.length; i += chunkSize) {
if (buffer.length <= i + chunkSize) { if (buffer.length <= i + chunkSize) {
break; break;
} }
bytes = buffer.sublist(i, i + chunkSize); bytes = buffer.sublist(i, i + chunkSize);
if ((counter % 3) == 0) { if ((counter % 3) == 0) {
bytes = decryptChunk(key, bytes); bytes = decryptChunk(key, bytes);
} }
if (dropBytes > 0) { if (dropBytes > 0) {
bytes = bytes.sublist(dropBytes); bytes = bytes.sublist(dropBytes);
dropBytes = 0; dropBytes = 0;
} }
counter++; counter++;
yield bytes; yield bytes;
} }
if (i < buffer.length) { if (i < buffer.length) {
buffer.removeRange(0, i); buffer.removeRange(0, i);
} else { } else {
buffer.clear(); buffer.clear();
} }
} }
// add remaining items in buffer // add remaining items in buffer
if (buffer.isNotEmpty) { if (buffer.isNotEmpty) {
if (dropBytes > 0) { if (dropBytes > 0) {
yield buffer.sublist(dropBytes); yield buffer.sublist(dropBytes);
return; return;
} }
yield buffer; yield buffer;
} }
} }
Future<Uri?> _getUrl() async { Future<Uri?> _getUrl() async {
final String actualTrackToken; final String actualTrackToken;
if (DateTime.now().millisecondsSinceEpoch ~/ 1000 > trackTokenExpiration) { if (DateTime.now().millisecondsSinceEpoch ~/ 1000 > trackTokenExpiration) {
if (!deezerAPI.canStreamHQ && !deezerAPI.canStreamLossless) { if (!deezerAPI.canStreamHQ && !deezerAPI.canStreamLossless) {
_logger.fine('using old url generation, token expired.'); _logger.fine('using old url generation, token expired.');
} }
final newTrack = await deezerAPI.track(trackId); final newTrack = await deezerAPI.track(trackId);
actualTrackToken = newTrack.trackToken!; actualTrackToken = newTrack.trackToken!;
} else { } else {
actualTrackToken = trackToken; actualTrackToken = trackToken;
} }
final res = await deezerAPI.getTrackUrl( final res = await deezerAPI.getTrackUrl(
actualTrackToken, _currentQuality!.toDeezerQualityString()); actualTrackToken, _currentQuality!.toDeezerQualityString());
if (res.error != null) { if (res.error != null) {
_logger.warning('Error while getting track url: ${res.error!}'); _logger.warning('Error while getting track url: ${res.error!}');
return null; return null;
} }
if (res.sources == null) { if (res.sources == null) {
_logger.warning('Error while getting track url: No sources!'); _logger.warning('Error while getting track url: No sources!');
return null; return null;
} }
return Uri.parse(res.sources![0].url); return Uri.parse(res.sources![0].url);
} }
@override @override
Future<StreamAudioResponse> request([int? start, int? end]) async { Future<StreamAudioResponse> request([int? start, int? end]) async {
start ??= 0; start ??= 0;
if (_cachedSourceLength != null) { if (_cachedSourceLength != null) {
if (start == _cachedSourceLength) { if (start == _cachedSourceLength) {
return StreamAudioResponse( return StreamAudioResponse(
sourceLength: _cachedSourceLength, sourceLength: _cachedSourceLength,
contentLength: 0, contentLength: 0,
offset: start, offset: start,
stream: const Stream<List<int>>.empty(), stream: const Stream<List<int>>.empty(),
contentType: _cachedContentType!); contentType: _cachedContentType!);
} }
} }
_logger.fine("authorizing..."); _logger.fine("authorizing...");
if (!await deezerAPI.authorize()) { if (!await deezerAPI.authorize()) {
_logger.severe("authorization failed! cannot continue!"); _logger.severe("authorization failed! cannot continue!");
throw Exception("Authorization failed!"); throw Exception("Authorization failed!");
} }
// determine quality to use // determine quality to use
final newQuality = _getQuality.call(); final newQuality = _getQuality.call();
if (_downloadUrl != null && _currentQuality != newQuality) { if (_downloadUrl != null && _currentQuality != newQuality) {
// update currentUrl to get tracks with new quality // update currentUrl to get tracks with new quality
_downloadUrl = null; _downloadUrl = null;
} }
_currentQuality = newQuality; _currentQuality = newQuality;
if (_downloadUrl == null) { if (_downloadUrl == null) {
final gottenUrl = await _getUrl(); final gottenUrl = await _getUrl();
if (gottenUrl != null) { if (gottenUrl != null) {
_downloadUrl = gottenUrl; _downloadUrl = gottenUrl;
} else { } else {
_logger.warning('falling back to old url generation!'); _logger.warning('falling back to old url generation!');
// OLD URL GENERATION // OLD URL GENERATION
try { try {
_downloadUrl = await _fallbackUrl(); _downloadUrl = await _fallbackUrl();
} on QualityException { } on QualityException {
rethrow; rethrow;
} }
} }
} }
_logger.fine("Downloading track from ${_downloadUrl!.toString()}"); _logger.fine("Downloading track from ${_downloadUrl!.toString()}");
final int deezerStart = start - (start % 2048); final int deezerStart = start - (start % 2048);
final req = http.Request('GET', _downloadUrl!) final req = http.Request('GET', _downloadUrl!)
..headers.addAll({ ..headers.addAll({
'User-Agent': deezerAPI.headers['User-Agent']!, 'User-Agent': deezerAPI.headers['User-Agent']!,
'Accept-Language': '*', 'Accept-Language': '*',
'Accept': '*/*', 'Accept': '*/*',
if (deezerStart > 0) if (deezerStart > 0)
"Range": "bytes=$deezerStart-${end == null ? '' : end.toString()}" "Range": "bytes=$deezerStart-${end == null ? '' : end.toString()}"
}); });
final res = await req.send(); final res = await req.send();
final rc = res.statusCode; final rc = res.statusCode;
_logger _logger
.finest("request sent! rc: $rc, content-length: ${res.contentLength}"); .finest("request sent! rc: $rc, content-length: ${res.contentLength}");
onStreamObtained?.call(StreamQualityInfo( onStreamObtained?.call(StreamQualityInfo(
format: quality == AudioQuality.FLAC ? Format.FLAC : Format.MP3, format: quality == AudioQuality.FLAC ? Format.FLAC : Format.MP3,
source: Source.stream, source: Source.stream,
size: start + res.contentLength!, size: start + res.contentLength!,
quality: quality, quality: quality,
)); ));
if (rc != HttpStatus.ok && rc != HttpStatus.partialContent) { if (rc != HttpStatus.ok && rc != HttpStatus.partialContent) {
throw Exception(await res.stream.bytesToString()); throw Exception(await res.stream.bytesToString());
} }
int dropBytes = start % chunkSize; int dropBytes = start % chunkSize;
_logger.finest( _logger.finest(
"deezerStart: $deezerStart (actual start: $start), end: $end, dropBytes: $dropBytes"); "deezerStart: $deezerStart (actual start: $start), end: $end, dropBytes: $dropBytes");
final stream = decryptionStream(res.stream, start: start, trackId: trackId); final stream = decryptionStream(res.stream, start: start, trackId: trackId);
final cl = res.contentLength! - dropBytes; final cl = res.contentLength! - dropBytes;
if (end == null) { if (end == null) {
_cachedSourceLength = cl + start; _cachedSourceLength = cl + start;
} }
return StreamAudioResponse( return StreamAudioResponse(
sourceLength: _cachedSourceLength, sourceLength: _cachedSourceLength,
contentLength: cl, contentLength: cl,
offset: start, offset: start,
stream: stream, stream: stream,
contentType: _cachedContentType = contentType: _cachedContentType =
quality == AudioQuality.FLAC ? "audio/flac" : "audio/mpeg"); quality == AudioQuality.FLAC ? "audio/flac" : "audio/mpeg");
} }
} }

View File

@ -1,3 +1,3 @@
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
class T {} class T {}

View File

@ -1,30 +1,30 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter_background_service/flutter_background_service.dart'; import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:freezer/api/download_manager/download_service.dart'; import 'package:freezer/api/download_manager/download_service.dart';
import 'package:freezer/translations.i18n.dart'; import 'package:freezer/translations.i18n.dart';
class DownloadManager { class DownloadManager {
Future<bool> startService() { Future<bool> startService() {
if (Platform.isAndroid) { if (Platform.isAndroid) {
return FlutterBackgroundService().configure( return FlutterBackgroundService().configure(
iosConfiguration: IosConfiguration(), // fuck ios iosConfiguration: IosConfiguration(), // fuck ios
androidConfiguration: AndroidConfiguration( androidConfiguration: AndroidConfiguration(
onStart: _startService, onStart: _startService,
isForegroundMode: false, isForegroundMode: false,
autoStart: false, autoStart: false,
autoStartOnBoot: false, autoStartOnBoot: false,
foregroundServiceNotificationId: DownloadService.NOTIFICATION_ID, foregroundServiceNotificationId: DownloadService.NOTIFICATION_ID,
notificationChannelId: DownloadService.NOTIFICATION_CHANNEL_ID, notificationChannelId: DownloadService.NOTIFICATION_CHANNEL_ID,
initialNotificationTitle: 'Freezer'.i18n, initialNotificationTitle: 'Freezer'.i18n,
initialNotificationContent: 'Starting download service...'.i18n, initialNotificationContent: 'Starting download service...'.i18n,
)); ));
} }
_startService(null); _startService(null);
return Future.value(true); return Future.value(true);
} }
static void _startService(ServiceInstance? service) => static void _startService(ServiceInstance? service) =>
DownloadService(service).run(); DownloadService(service).run();
} }

View File

@ -1,11 +1,11 @@
import 'package:flutter_background_service/flutter_background_service.dart'; import 'package:flutter_background_service/flutter_background_service.dart';
class DownloadService { class DownloadService {
static const NOTIFICATION_ID = 6969; static const NOTIFICATION_ID = 6969;
static const NOTIFICATION_CHANNEL_ID = "freezerdownloads"; static const NOTIFICATION_CHANNEL_ID = "freezerdownloads";
final ServiceInstance? service; final ServiceInstance? service;
DownloadService(this.service); DownloadService(this.service);
void run() {} void run() {}
} }

View File

@ -1,34 +1,34 @@
import 'dart:io'; import 'dart:io';
import 'package:freezer/api/definitions.dart'; import 'package:freezer/api/definitions.dart';
import 'package:just_audio/just_audio.dart'; import 'package:just_audio/just_audio.dart';
class OfflineAudioSource extends StreamAudioSource { class OfflineAudioSource extends StreamAudioSource {
final File file; final File file;
final StreamInfoCallback? onStreamObtained; final StreamInfoCallback? onStreamObtained;
OfflineAudioSource(this.file, {this.onStreamObtained}); OfflineAudioSource(this.file, {this.onStreamObtained});
@override @override
Future<StreamAudioResponse> request([int? start, int? end]) async { Future<StreamAudioResponse> request([int? start, int? end]) async {
// determine content type // determine content type
final first = await file.openRead(0, 4).join(); final first = await file.openRead(0, 4).join();
bool isFlac = false; bool isFlac = false;
if (first == 'fLaC') isFlac = true; if (first == 'fLaC') isFlac = true;
final length = await file.length(); final length = await file.length();
final stream = file.openRead(start, end); final stream = file.openRead(start, end);
onStreamObtained?.call(StreamQualityInfo( onStreamObtained?.call(StreamQualityInfo(
format: isFlac ? Format.FLAC : Format.MP3, format: isFlac ? Format.FLAC : Format.MP3,
source: Source.offline, source: Source.offline,
quality: null, quality: null,
size: length)); size: length));
return StreamAudioResponse( return StreamAudioResponse(
sourceLength: length, sourceLength: length,
contentLength: (end ?? length) - (start ?? 0), contentLength: (end ?? length) - (start ?? 0),
offset: start, offset: start,
stream: stream, stream: stream,
contentType: isFlac ? 'audio/flac' : 'audio/mpeg'); contentType: isFlac ? 'audio/flac' : 'audio/mpeg');
} }
} }

View File

@ -1,49 +1,54 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
class Paths { class Paths {
static Future<String> dataDirectory() async { static Future<String> dataDirectory() async {
switch (defaultTargetPlatform) { switch (defaultTargetPlatform) {
case TargetPlatform.linux: case TargetPlatform.linux:
final home = Platform.environment['HOME']; final home = Platform.environment['HOME'];
if (home == null) return path.dirname(Platform.resolvedExecutable); if (home == null) return path.dirname(Platform.resolvedExecutable);
if (await Directory(path.join(home, '.local', 'share')).exists()) { if (await Directory(path.join(home, '.local', 'share')).exists()) {
final target = final target =
await Directory(path.join(home, '.local', 'share', 'freezer')) await Directory(path.join(home, '.local', 'share', 'freezer'))
.create(); .create();
return target.path; return target.path;
} }
return path.dirname(Platform.resolvedExecutable); return path.dirname(Platform.resolvedExecutable);
case TargetPlatform.windows: case TargetPlatform.windows:
String? home = Platform.environment['USERPROFILE']; final String? localAppData = Platform.environment['LOCALAPPDATA'];
if (home == null) { if (localAppData != null) {
final drive = Platform.environment['HOMEDRIVE']; final target = await Directory(path.join(localAppData, 'Freezer')).create();
final homepath = Platform.environment['HOMEPATH']; return target.path;
if (drive == null || homepath == null) { }
return path.dirname(Platform.resolvedExecutable); String? home = Platform.environment['USERPROFILE'];
} if (home == null) {
final drive = Platform.environment['HOMEDRIVE'];
home = drive + homepath; final homepath = Platform.environment['HOMEPATH'];
} if (drive == null || homepath == null) {
return path.dirname(Platform.resolvedExecutable);
final target = }
await Directory(path.join(home, 'AppData', 'Freezer')).create();
return target.path; home = drive + homepath;
default: }
return (await getApplicationDocumentsDirectory()).path;
} final target =
} await Directory(path.join(home, 'AppData', 'Local', 'Freezer')).create();
return target.path;
static Future<String> cacheDir() async { default:
if (Platform.isLinux || Platform.isWindows) { return (await getApplicationDocumentsDirectory()).path;
final dataDir = await dataDirectory(); }
final target = await Directory(path.join(dataDir, 'cache')).create(); }
return target.path;
} static Future<String> cacheDir() async {
if (Platform.isLinux || Platform.isWindows) {
return (await getTemporaryDirectory()).path; final dataDir = await dataDirectory();
} final target = await Directory(path.join(dataDir, 'cache')).create();
} return target.path;
}
return (await getTemporaryDirectory()).path;
}
}

View File

@ -1,304 +1,304 @@
import 'dart:async'; import 'dart:async';
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:equalizer/equalizer.dart'; import 'package:equalizer/equalizer.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:freezer/api/cache.dart'; import 'package:freezer/api/cache.dart';
import 'package:freezer/api/deezer.dart'; import 'package:freezer/api/deezer.dart';
import 'package:freezer/api/definitions.dart'; import 'package:freezer/api/definitions.dart';
import 'package:freezer/api/player/audio_handler.dart'; import 'package:freezer/api/player/audio_handler.dart';
import 'package:freezer/settings.dart'; import 'package:freezer/settings.dart';
import 'package:freezer/translations.i18n.dart'; import 'package:freezer/translations.i18n.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
class PlayerHelper { class PlayerHelper {
late StreamSubscription _customEventSubscription; late StreamSubscription _customEventSubscription;
late StreamSubscription _mediaItemSubscription; late StreamSubscription _mediaItemSubscription;
late StreamSubscription _playbackStateStreamSubscription; late StreamSubscription _playbackStateStreamSubscription;
QueueSource? queueSource; QueueSource? queueSource;
AudioServiceRepeatMode repeatType = AudioServiceRepeatMode.none; AudioServiceRepeatMode repeatType = AudioServiceRepeatMode.none;
int? audioSession; int? audioSession;
int? _prevAudioSession; int? _prevAudioSession;
bool equalizerOpen = false; bool equalizerOpen = false;
bool _shuffleEnabled = false; bool _shuffleEnabled = false;
int _queueIndex = 0; int _queueIndex = 0;
bool _started = false; bool _started = false;
/// Whether this system supports the [Connectivity] plugin or not /// Whether this system supports the [Connectivity] plugin or not
bool _isConnectivityPluginAvailable = true; bool _isConnectivityPluginAvailable = true;
bool get isConnectivityPluginAvailable => _isConnectivityPluginAvailable; bool get isConnectivityPluginAvailable => _isConnectivityPluginAvailable;
//Visualizer //Visualizer
// StreamController _visualizerController = StreamController.broadcast(); // StreamController _visualizerController = StreamController.broadcast();
// Stream get visualizerStream => _visualizerController.stream; // Stream get visualizerStream => _visualizerController.stream;
final _streamInfoSubject = BehaviorSubject<StreamQualityInfo>(); final _streamInfoSubject = BehaviorSubject<StreamQualityInfo>();
ValueStream<StreamQualityInfo> get streamInfo => _streamInfoSubject.stream; ValueStream<StreamQualityInfo> get streamInfo => _streamInfoSubject.stream;
final _bufferPositionSubject = BehaviorSubject<Duration>(); final _bufferPositionSubject = BehaviorSubject<Duration>();
ValueStream<Duration> get bufferPosition => _bufferPositionSubject.stream; ValueStream<Duration> get bufferPosition => _bufferPositionSubject.stream;
/// Find queue index by id /// Find queue index by id
/// ///
/// The function gets more expensive the longer the queue is and the further the element is from the beginning. /// The function gets more expensive the longer the queue is and the further the element is from the beginning.
int getQueueIndexFromId() => audioHandler.mediaItem.value == null int getQueueIndexFromId() => audioHandler.mediaItem.value == null
? -1 ? -1
: audioHandler.queue.value : audioHandler.queue.value
.indexWhere((mi) => mi.id == audioHandler.mediaItem.value!.id); .indexWhere((mi) => mi.id == audioHandler.mediaItem.value!.id);
int getQueueIndex() => int getQueueIndex() =>
audioHandler.playbackState.value.queueIndex ?? getQueueIndexFromId(); audioHandler.playbackState.value.queueIndex ?? getQueueIndexFromId();
int get queueIndex => _queueIndex; int get queueIndex => _queueIndex;
Future<void> initAudioHandler() async { Future<void> initAudioHandler() async {
final initArgs = AudioPlayerTaskInitArguments.from( final initArgs = AudioPlayerTaskInitArguments.from(
settings: settings, deezerAPI: deezerAPI); settings: settings, deezerAPI: deezerAPI);
// initialize our audiohandler instance // initialize our audiohandler instance
audioHandler = await AudioService.init( audioHandler = await AudioService.init(
builder: () => AudioPlayerTask(initArgs), builder: () => AudioPlayerTask(initArgs),
config: AudioServiceConfig( config: AudioServiceConfig(
notificationColor: settings.primaryColor, notificationColor: settings.primaryColor,
androidStopForegroundOnPause: false, androidStopForegroundOnPause: false,
androidNotificationOngoing: false, androidNotificationOngoing: false,
androidNotificationClickStartsActivity: true, androidNotificationClickStartsActivity: true,
androidNotificationChannelDescription: 'Freezer', androidNotificationChannelDescription: 'Freezer',
androidNotificationChannelName: 'Freezer', androidNotificationChannelName: 'Freezer',
androidNotificationIcon: 'drawable/ic_logo', androidNotificationIcon: 'drawable/ic_logo',
preloadArtwork: false, preloadArtwork: false,
), ),
); );
} }
Future<void> start() async { Future<void> start() async {
if (_started) return; if (_started) return;
_started = true; _started = true;
//Subscribe to custom events //Subscribe to custom events
_customEventSubscription = audioHandler.customEvent.listen((event) async { _customEventSubscription = audioHandler.customEvent.listen((event) async {
if (event is! Map) return; if (event is! Map) return;
Logger('PlayerHelper').fine("event received: ${event['action']}"); Logger('PlayerHelper').fine("event received: ${event['action']}");
switch (event['action']) { switch (event['action']) {
case 'onLoad': case 'onLoad':
//After audio_service is loaded, load queue, set quality //After audio_service is loaded, load queue, set quality
await settings.updateAudioServiceQuality(); await settings.updateAudioServiceQuality();
break; break;
case 'onRestore': case 'onRestore':
//Load queueSource from isolate //Load queueSource from isolate
queueSource = event['queueSource'] as QueueSource; queueSource = event['queueSource'] as QueueSource;
repeatType = event['repeatMode'] as AudioServiceRepeatMode; repeatType = event['repeatMode'] as AudioServiceRepeatMode;
_queueIndex = getQueueIndex(); _queueIndex = getQueueIndex();
break; break;
case 'audioSession': case 'audioSession':
if (!settings.enableEqualizer) break; if (!settings.enableEqualizer) break;
//Save //Save
_prevAudioSession = audioSession; _prevAudioSession = audioSession;
audioSession = event['id']; audioSession = event['id'];
if (audioSession == null) break; if (audioSession == null) break;
//Open EQ //Open EQ
if (!equalizerOpen) { if (!equalizerOpen) {
Equalizer.open(event['id']); Equalizer.open(event['id']);
equalizerOpen = true; equalizerOpen = true;
break; break;
} }
//Change session id //Change session id
if (_prevAudioSession != audioSession) { if (_prevAudioSession != audioSession) {
if (_prevAudioSession != null) { if (_prevAudioSession != null) {
Equalizer.removeAudioSessionId(_prevAudioSession!); Equalizer.removeAudioSessionId(_prevAudioSession!);
} }
Equalizer.setAudioSessionId(audioSession!); Equalizer.setAudioSessionId(audioSession!);
} }
break; break;
//Visualizer data //Visualizer data
// case 'visualizer': // case 'visualizer':
// _visualizerController.add(event['data']); // _visualizerController.add(event['data']);
// break; // break;
case 'streamInfo': case 'streamInfo':
Logger('PlayerHelper').fine("streamInfo received"); Logger('PlayerHelper').fine("streamInfo received");
_streamInfoSubject.add(event['data'] as StreamQualityInfo); _streamInfoSubject.add(event['data'] as StreamQualityInfo);
break; break;
case 'bufferPosition': case 'bufferPosition':
_bufferPositionSubject.add(event['data'] as Duration); _bufferPositionSubject.add(event['data'] as Duration);
break; break;
case 'connectivityPlugin': case 'connectivityPlugin':
_isConnectivityPluginAvailable = event['available'] as bool; _isConnectivityPluginAvailable = event['available'] as bool;
break; break;
} }
}); });
_mediaItemSubscription = audioHandler.mediaItem.listen((mediaItem) async { _mediaItemSubscription = audioHandler.mediaItem.listen((mediaItem) async {
if (mediaItem == null) return; if (mediaItem == null) return;
_queueIndex = getQueueIndex(); _queueIndex = getQueueIndex();
//Load more flow if last song (not using .last since it iterates through previous elements first) //Load more flow if last song (not using .last since it iterates through previous elements first)
//Save queue //Save queue
await audioHandler.customAction('saveQueue', {}); await audioHandler.customAction('saveQueue', {});
//Add to history //Add to history
if (cache.history.isNotEmpty && cache.history.last.id == mediaItem.id) { if (cache.history.isNotEmpty && cache.history.last.id == mediaItem.id) {
return; return;
} }
cache.history.add(Track.fromMediaItem(mediaItem)); cache.history.add(Track.fromMediaItem(mediaItem));
cache.save(); cache.save();
}); });
//Start audio_service //Start audio_service
// await startService(); it is already ready, there is no need to start it // await startService(); it is already ready, there is no need to start it
} }
Future<void> authorizeLastFM() async { Future<void> authorizeLastFM() async {
if (settings.lastFMUsername == null || settings.lastFMPassword == null) { if (settings.lastFMUsername == null || settings.lastFMPassword == null) {
return; return;
} }
await audioHandler.customAction('authorizeLastFM', { await audioHandler.customAction('authorizeLastFM', {
'username': settings.lastFMUsername, 'username': settings.lastFMUsername,
'password': settings.lastFMPassword 'password': settings.lastFMPassword
}); });
} }
Future<bool> toggleShuffle() async { Future<bool> toggleShuffle() async {
_shuffleEnabled = !_shuffleEnabled; _shuffleEnabled = !_shuffleEnabled;
await audioHandler.setShuffleMode(_shuffleEnabled await audioHandler.setShuffleMode(_shuffleEnabled
? AudioServiceShuffleMode.all ? AudioServiceShuffleMode.all
: AudioServiceShuffleMode.none); : AudioServiceShuffleMode.none);
return _shuffleEnabled; return _shuffleEnabled;
} }
bool get shuffleEnabled => _shuffleEnabled; bool get shuffleEnabled => _shuffleEnabled;
//Repeat toggle //Repeat toggle
Future changeRepeat() async { Future changeRepeat() async {
//Change to next repeat type //Change to next repeat type
repeatType = repeatType == AudioServiceRepeatMode.all repeatType = repeatType == AudioServiceRepeatMode.all
? AudioServiceRepeatMode.none ? AudioServiceRepeatMode.none
: repeatType == AudioServiceRepeatMode.none : repeatType == AudioServiceRepeatMode.none
? AudioServiceRepeatMode.one ? AudioServiceRepeatMode.one
: AudioServiceRepeatMode.all; : AudioServiceRepeatMode.all;
//Set repeat type //Set repeat type
await audioHandler.setRepeatMode(repeatType); await audioHandler.setRepeatMode(repeatType);
} }
//Executed before exit //Executed before exit
Future onExit() async { Future onExit() async {
_customEventSubscription.cancel(); _customEventSubscription.cancel();
_playbackStateStreamSubscription.cancel(); _playbackStateStreamSubscription.cancel();
_mediaItemSubscription.cancel(); _mediaItemSubscription.cancel();
} }
//Replace queue, play specified track id //Replace queue, play specified track id
Future<void> _loadQueuePlay(List<MediaItem> queue, String? trackId) async { Future<void> _loadQueuePlay(List<MediaItem> queue, String? trackId) async {
await settings.updateAudioServiceQuality(); await settings.updateAudioServiceQuality();
await audioHandler.customAction('setIndex', { await audioHandler.customAction('setIndex', {
'index': trackId == null ? 0 : queue.indexWhere((m) => m.id == trackId) 'index': trackId == null ? 0 : queue.indexWhere((m) => m.id == trackId)
}); });
await audioHandler.updateQueue(queue); await audioHandler.updateQueue(queue);
// if (queue[0].id != trackId) // if (queue[0].id != trackId)
// await AudioService.skipToQueueItem(trackId); // await AudioService.skipToQueueItem(trackId);
if (!audioHandler.playbackState.value.playing) audioHandler.play(); if (!audioHandler.playbackState.value.playing) audioHandler.play();
} }
//Play track from album //Play track from album
Future playFromAlbum(Album album, [String? trackId]) async { Future playFromAlbum(Album album, [String? trackId]) async {
await playFromTrackList(album.tracks!, trackId, await playFromTrackList(album.tracks!, trackId,
QueueSource(id: album.id, text: album.title, source: 'album')); QueueSource(id: album.id, text: album.title, source: 'album'));
} }
//Play mix by track //Play mix by track
Future playMix(String trackId, String trackTitle) async { Future playMix(String trackId, String trackTitle) async {
List<Track> tracks = (await deezerAPI.playMix(trackId))!; List<Track> tracks = (await deezerAPI.playMix(trackId))!;
playFromTrackList( playFromTrackList(
tracks, tracks,
tracks[0].id, tracks[0].id,
QueueSource( QueueSource(
id: trackId, id: trackId,
text: '${'Mix based on'.i18n} $trackTitle', text: '${'Mix based on'.i18n} $trackTitle',
source: 'mix')); source: 'mix'));
} }
//Play from artist top tracks //Play from artist top tracks
Future playFromTopTracks( Future playFromTopTracks(
List<Track> tracks, String trackId, Artist artist) async { List<Track> tracks, String trackId, Artist artist) async {
await playFromTrackList( await playFromTrackList(
tracks, tracks,
trackId, trackId,
QueueSource( QueueSource(
id: artist.id, text: 'Top ${artist.name}', source: 'topTracks')); id: artist.id, text: 'Top ${artist.name}', source: 'topTracks'));
} }
Future playFromPlaylist(Playlist playlist, [String? trackId]) async { Future playFromPlaylist(Playlist playlist, [String? trackId]) async {
await playFromTrackList(playlist.tracks!, trackId, await playFromTrackList(playlist.tracks!, trackId,
QueueSource(id: playlist.id, text: playlist.title, source: 'playlist')); QueueSource(id: playlist.id, text: playlist.title, source: 'playlist'));
} }
//Play episode from show, load whole show as queue //Play episode from show, load whole show as queue
Future<void> playShowEpisode(Show show, List<ShowEpisode> episodes, Future<void> playShowEpisode(Show show, List<ShowEpisode> episodes,
{int index = 0}) async { {int index = 0}) async {
QueueSource queueSource = QueueSource queueSource =
QueueSource(id: show.id, text: show.name, source: 'show'); QueueSource(id: show.id, text: show.name, source: 'show');
//Generate media items //Generate media items
List<MediaItem> queue = List<MediaItem> queue =
episodes.map<MediaItem>((e) => e.toMediaItem(show)).toList(); episodes.map<MediaItem>((e) => e.toMediaItem(show)).toList();
//Load and play //Load and play
// await startService(); // audioservice is ready // await startService(); // audioservice is ready
await settings.updateAudioServiceQuality(); await settings.updateAudioServiceQuality();
await setQueueSource(queueSource); await setQueueSource(queueSource);
await audioHandler.customAction('setIndex', {'index': index}); await audioHandler.customAction('setIndex', {'index': index});
await audioHandler.updateQueue(queue); await audioHandler.updateQueue(queue);
if (!audioHandler.playbackState.value.playing) audioHandler.play(); if (!audioHandler.playbackState.value.playing) audioHandler.play();
} }
//Load tracks as queue, play track id, set queue source //Load tracks as queue, play track id, set queue source
Future playFromTrackList( Future playFromTrackList(
List<Track?> tracks, String? trackId, QueueSource queueSource) async { List<Track?> tracks, String? trackId, QueueSource queueSource) async {
final queue = await Future.wait(tracks final queue = await Future.wait(tracks
.map<Future<MediaItem>>((track) => track!.toMediaItem()) .map<Future<MediaItem>>((track) => track!.toMediaItem())
.toList()); .toList());
await setQueueSource(queueSource); await setQueueSource(queueSource);
await _loadQueuePlay(queue, trackId); await _loadQueuePlay(queue, trackId);
} }
//Load smart track list as queue, start from beginning //Load smart track list as queue, start from beginning
Future playFromSmartTrackList(SmartTrackList stl) async { Future playFromSmartTrackList(SmartTrackList stl) async {
//Load from API if no tracks //Load from API if no tracks
if (stl.tracks == null || stl.tracks!.isEmpty) { if (stl.tracks == null || stl.tracks!.isEmpty) {
if (settings.offlineMode) { if (settings.offlineMode) {
Fluttertoast.showToast( Fluttertoast.showToast(
msg: "Offline mode, can't play flow or smart track lists.".i18n, msg: "Offline mode, can't play flow or smart track lists.".i18n,
gravity: ToastGravity.BOTTOM, gravity: ToastGravity.BOTTOM,
toastLength: Toast.LENGTH_SHORT); toastLength: Toast.LENGTH_SHORT);
return; return;
} }
//Flow songs cannot be accessed by smart track list call //Flow songs cannot be accessed by smart track list call
if (stl.id! == 'flow') { if (stl.id! == 'flow') {
stl.tracks = await deezerAPI.flow(stl.flowConfig); stl.tracks = await deezerAPI.flow(stl.flowConfig);
} else { } else {
stl = await deezerAPI.smartTrackList(stl.id); stl = await deezerAPI.smartTrackList(stl.id);
} }
} }
QueueSource queueSource = QueueSource( QueueSource queueSource = QueueSource(
id: stl.flowConfig ?? stl.id, id: stl.flowConfig ?? stl.id,
source: (stl.id == 'flow') ? 'flow' : 'smarttracklist', source: (stl.id == 'flow') ? 'flow' : 'smarttracklist',
text: stl.title ?? text: stl.title ??
((stl.id == 'flow') ? 'Flow'.i18n : 'Smart track list'.i18n)); ((stl.id == 'flow') ? 'Flow'.i18n : 'Smart track list'.i18n));
await playFromTrackList(stl.tracks!, stl.tracks![0].id, queueSource); await playFromTrackList(stl.tracks!, stl.tracks![0].id, queueSource);
} }
Future setQueueSource(QueueSource queueSource) async { Future setQueueSource(QueueSource queueSource) async {
this.queueSource = queueSource; this.queueSource = queueSource;
await audioHandler.customAction('queueSource', queueSource.toJson()); await audioHandler.customAction('queueSource', queueSource.toJson());
} }
//Reorder tracks in queue //Reorder tracks in queue
Future reorder(int oldIndex, int newIndex) => audioHandler Future reorder(int oldIndex, int newIndex) => audioHandler
.customAction('reorder', {'oldIndex': oldIndex, 'newIndex': newIndex}); .customAction('reorder', {'oldIndex': oldIndex, 'newIndex': newIndex});
//Start visualizer //Start visualizer
// Future startVisualizer() async { // Future startVisualizer() async {
// await audioHandler.customAction('startVisualizer'); // await audioHandler.customAction('startVisualizer');
// } // }
//Stop visualizer //Stop visualizer
// Future stopVisualizer() async { // Future stopVisualizer() async {
// await audioHandler.customAction('stopVisualizer'); // await audioHandler.customAction('stopVisualizer');
// } // }
} }

View File

@ -1,39 +1,39 @@
import 'package:freezer/api/definitions.dart'; import 'package:freezer/api/definitions.dart';
import 'package:just_audio/just_audio.dart'; import 'package:just_audio/just_audio.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'deezer.dart'; import 'deezer.dart';
class UrlAudioSource extends StreamAudioSource { class UrlAudioSource extends StreamAudioSource {
final Uri uri; final Uri uri;
final StreamInfoCallback? onStreamObtained; final StreamInfoCallback? onStreamObtained;
UrlAudioSource(this.uri, {this.onStreamObtained}); UrlAudioSource(this.uri, {this.onStreamObtained});
@override @override
Future<StreamAudioResponse> request([int? start, int? end]) async { Future<StreamAudioResponse> request([int? start, int? end]) async {
final req = http.Request('GET', uri) final req = http.Request('GET', uri)
..headers.addAll({ ..headers.addAll({
'User-Agent': deezerAPI.headers['User-Agent']!, 'User-Agent': deezerAPI.headers['User-Agent']!,
'Accept-Language': '*', 'Accept-Language': '*',
'Accept': '*/*', 'Accept': '*/*',
if (start != null || end != null) if (start != null || end != null)
"Range": "Range":
"bytes=${start == null ? '' : start.toString()}-${end == null ? '' : end.toString()}" "bytes=${start == null ? '' : start.toString()}-${end == null ? '' : end.toString()}"
}); });
final res = await req.send(); final res = await req.send();
onStreamObtained?.call(StreamQualityInfo( onStreamObtained?.call(StreamQualityInfo(
format: Format.MP3, format: Format.MP3,
source: Source.stream, source: Source.stream,
quality: null, quality: null,
size: res.contentLength! + (start ?? 0))); size: res.contentLength! + (start ?? 0)));
return StreamAudioResponse( return StreamAudioResponse(
sourceLength: res.contentLength! + (start ?? 0), sourceLength: res.contentLength! + (start ?? 0),
contentLength: res.contentLength!, contentLength: res.contentLength!,
offset: start, offset: start,
stream: res.stream, stream: res.stream,
contentType: res.headers['content-type']!); contentType: res.headers['content-type']!);
} }
} }

View File

@ -1,195 +1,195 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class FancyScaffold extends StatefulWidget { class FancyScaffold extends StatefulWidget {
final Widget bottomPanel; final Widget bottomPanel;
final double bottomPanelHeight; final double bottomPanelHeight;
final Widget expandedPanel; final Widget expandedPanel;
final Widget? bottomNavigationBar; final Widget? bottomNavigationBar;
final Widget? drawer; final Widget? drawer;
final Widget? navigationRail; final Widget? navigationRail;
final Widget body; final Widget body;
final void Function(AnimationStatus)? onAnimationStatusChange; final void Function(AnimationStatus)? onAnimationStatusChange;
const FancyScaffold({ const FancyScaffold({
required this.bottomPanel, required this.bottomPanel,
required this.bottomPanelHeight, required this.bottomPanelHeight,
required this.expandedPanel, required this.expandedPanel,
required this.body, required this.body,
this.onAnimationStatusChange, this.onAnimationStatusChange,
this.bottomNavigationBar, this.bottomNavigationBar,
this.navigationRail, this.navigationRail,
this.drawer, this.drawer,
super.key, super.key,
}); });
static FancyScaffoldState? of(BuildContext context) => static FancyScaffoldState? of(BuildContext context) =>
context.findAncestorStateOfType<FancyScaffoldState>(); context.findAncestorStateOfType<FancyScaffoldState>();
@override @override
FancyScaffoldState createState() => FancyScaffoldState(); FancyScaffoldState createState() => FancyScaffoldState();
} }
class FancyScaffoldState extends State<FancyScaffold> class FancyScaffoldState extends State<FancyScaffold>
with TickerProviderStateMixin { with TickerProviderStateMixin {
// goes from 0 to 1 (double) // goes from 0 to 1 (double)
// 0 = preview, 1 = expanded // 0 = preview, 1 = expanded
late final AnimationController dragController; late final AnimationController dragController;
final statusNotifier = final statusNotifier =
ValueNotifier<AnimationStatus>(AnimationStatus.dismissed); ValueNotifier<AnimationStatus>(AnimationStatus.dismissed);
@override @override
void initState() { void initState() {
dragController = AnimationController( dragController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 500)); vsync: this, duration: const Duration(milliseconds: 500));
dragController.addStatusListener((status) => statusNotifier.value = status); dragController.addStatusListener((status) => statusNotifier.value = status);
statusNotifier.addListener( statusNotifier.addListener(
() => widget.onAnimationStatusChange?.call(statusNotifier.value)); () => widget.onAnimationStatusChange?.call(statusNotifier.value));
super.initState(); super.initState();
} }
@override @override
void dispose() { void dispose() {
dragController.dispose(); dragController.dispose();
super.dispose(); super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final systemPadding = MediaQuery.of(context).viewPadding; final systemPadding = MediaQuery.of(context).viewPadding;
final defaultBottomPadding = final defaultBottomPadding =
(widget.bottomNavigationBar == null ? 0 : 80.0) + systemPadding.bottom; (widget.bottomNavigationBar == null ? 0 : 80.0) + systemPadding.bottom;
final screenHeight = MediaQuery.of(context).size.height; final screenHeight = MediaQuery.of(context).size.height;
final sizeAnimation = Tween<double>( final sizeAnimation = Tween<double>(
begin: widget.bottomPanelHeight / MediaQuery.of(context).size.height, begin: widget.bottomPanelHeight / MediaQuery.of(context).size.height,
end: 1.0, end: 1.0,
).animate(dragController); ).animate(dragController);
return WillPopScope( return WillPopScope(
onWillPop: () { onWillPop: () {
if (statusNotifier.value == AnimationStatus.completed || if (statusNotifier.value == AnimationStatus.completed ||
statusNotifier.value == AnimationStatus.reverse) { statusNotifier.value == AnimationStatus.reverse) {
dragController.fling(velocity: -1.0); dragController.fling(velocity: -1.0);
return Future.value(false); return Future.value(false);
} }
return Future.value(true); return Future.value(true);
}, },
child: Stack( child: Stack(
children: [ children: [
Positioned.fill( Positioned.fill(
child: Scaffold( child: Scaffold(
body: widget.navigationRail != null body: widget.navigationRail != null
? Row(children: [ ? Row(children: [
widget.navigationRail!, widget.navigationRail!,
const VerticalDivider( const VerticalDivider(
indent: 0.0, indent: 0.0,
endIndent: 0.0, endIndent: 0.0,
width: 2.0, width: 2.0,
), ),
Expanded(child: widget.body) Expanded(child: widget.body)
]) ])
: widget.body, : widget.body,
drawer: widget.drawer, drawer: widget.drawer,
bottomNavigationBar: Column( bottomNavigationBar: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SizedBox(height: widget.bottomPanelHeight), SizedBox(height: widget.bottomPanelHeight),
if (widget.bottomNavigationBar != null) if (widget.bottomNavigationBar != null)
SizeTransition( SizeTransition(
axisAlignment: -1.0, axisAlignment: -1.0,
sizeFactor: sizeFactor:
Tween(begin: 1.0, end: 0.0).animate(sizeAnimation), Tween(begin: 1.0, end: 0.0).animate(sizeAnimation),
child: widget.bottomNavigationBar, child: widget.bottomNavigationBar,
), ),
], ],
), ),
), ),
), ),
Positioned( Positioned(
bottom: 0, bottom: 0,
left: 0, left: 0,
right: 0, right: 0,
child: AnimatedBuilder( child: AnimatedBuilder(
animation: sizeAnimation, animation: sizeAnimation,
builder: (context, child) { builder: (context, child) {
final x = 1.0 - sizeAnimation.value; final x = 1.0 - sizeAnimation.value;
return Padding( return Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
bottom: (defaultBottomPadding /*+ 8.0*/) * x, bottom: (defaultBottomPadding /*+ 8.0*/) * x,
//right: 8.0 * x, //right: 8.0 * x,
//left: 8.0 * x, //left: 8.0 * x,
), ),
child: child, child: child,
); );
}, },
child: ValueListenableBuilder( child: ValueListenableBuilder(
valueListenable: statusNotifier, valueListenable: statusNotifier,
builder: (context, state, child) { builder: (context, state, child) {
return GestureDetector( return GestureDetector(
onVerticalDragEnd: _onVerticalDragEnd, onVerticalDragEnd: _onVerticalDragEnd,
onVerticalDragUpdate: _onVerticalDragUpdate, onVerticalDragUpdate: _onVerticalDragUpdate,
child: child, child: child,
); );
}, },
child: SizeTransition( child: SizeTransition(
sizeFactor: sizeAnimation, sizeFactor: sizeAnimation,
axisAlignment: -1.0, axisAlignment: -1.0,
axis: Axis.vertical, axis: Axis.vertical,
child: SizedBox( child: SizedBox(
height: screenHeight, height: screenHeight,
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
child: ValueListenableBuilder( child: ValueListenableBuilder(
valueListenable: statusNotifier, valueListenable: statusNotifier,
builder: (context, state, _) => Stack( builder: (context, state, _) => Stack(
children: [ children: [
if (state != AnimationStatus.dismissed) if (state != AnimationStatus.dismissed)
Positioned.fill( Positioned.fill(
key: const Key('player_screen'), key: const Key('player_screen'),
child: widget.expandedPanel, child: widget.expandedPanel,
), ),
if (state != AnimationStatus.completed) if (state != AnimationStatus.completed)
Positioned( Positioned(
top: 0, top: 0,
right: 0, right: 0,
left: 0, left: 0,
key: const Key('player_bar'), key: const Key('player_bar'),
child: FadeTransition( child: FadeTransition(
opacity: Tween(begin: 1.0, end: 0.0) opacity: Tween(begin: 1.0, end: 0.0)
.animate(dragController), .animate(dragController),
child: SizedBox( child: SizedBox(
height: widget.bottomPanelHeight, height: widget.bottomPanelHeight,
child: widget.bottomPanel), child: widget.bottomPanel),
), ),
), ),
], ],
), ),
), ),
)), )),
), ),
), ),
), ),
], ],
), ),
); );
} }
void _onVerticalDragUpdate(DragUpdateDetails details) { void _onVerticalDragUpdate(DragUpdateDetails details) {
dragController.value -= dragController.value -=
details.delta.dy / MediaQuery.of(context).size.height; details.delta.dy / MediaQuery.of(context).size.height;
} }
void _onVerticalDragEnd(DragEndDetails details) { void _onVerticalDragEnd(DragEndDetails details) {
// snap widget to size // snap widget to size
// this should be also handled by drag velocity and not only with bare size. // this should be also handled by drag velocity and not only with bare size.
const double minFlingVelocity = 365.0; const double minFlingVelocity = 365.0;
if (details.velocity.pixelsPerSecond.dy.abs() > minFlingVelocity) { if (details.velocity.pixelsPerSecond.dy.abs() > minFlingVelocity) {
dragController.fling( dragController.fling(
velocity: -details.velocity.pixelsPerSecond.dy / velocity: -details.velocity.pixelsPerSecond.dy /
MediaQuery.of(context).size.height); MediaQuery.of(context).size.height);
return; return;
} }
dragController.fling(velocity: dragController.value > 0.5 ? 1.0 : -1.0); dragController.fling(velocity: dragController.value > 0.5 ? 1.0 : -1.0);
} }
} }

2
linux/.gitignore vendored
View File

@ -1 +1 @@
flutter/ephemeral flutter/ephemeral

View File

@ -1,142 +1,142 @@
# Project-level configuration. # Project-level configuration.
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX) project(runner LANGUAGES CXX)
# The name of the executable created for the application. Change this to change # The name of the executable created for the application. Change this to change
# the on-disk name of your application. # the on-disk name of your application.
set(BINARY_NAME "freezer") set(BINARY_NAME "freezer")
# The unique GTK application identifier for this application. See: # The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID # https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "f.f.freezer") set(APPLICATION_ID "f.f.freezer")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent # Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake. # versions of CMake.
cmake_policy(SET CMP0063 NEW) cmake_policy(SET CMP0063 NEW)
# Load bundled libraries from the lib/ directory relative to the binary. # Load bundled libraries from the lib/ directory relative to the binary.
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
# Root filesystem for cross-building. # Root filesystem for cross-building.
if(FLUTTER_TARGET_PLATFORM_SYSROOT) if(FLUTTER_TARGET_PLATFORM_SYSROOT)
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif() endif()
# Define build configuration options. # Define build configuration options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE) STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release") "Debug" "Profile" "Release")
endif() endif()
# Compilation settings that should be applied to most targets. # Compilation settings that should be applied to most targets.
# #
# Be cautious about adding new options here, as plugins use this function by # Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead # default. In most cases, you should add new options to specific targets instead
# of modifying this function. # of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET) function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14) target_compile_features(${TARGET} PUBLIC cxx_std_14)
target_compile_options(${TARGET} PRIVATE -Wall -Werror) target_compile_options(${TARGET} PRIVATE -Wall -Werror)
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>") target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>") target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction() endfunction()
# Flutter library and tool build rules. # Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR}) add_subdirectory(${FLUTTER_MANAGED_DIR})
# System-level dependencies. # System-level dependencies.
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
# Define the application target. To change its name, change BINARY_NAME above, # Define the application target. To change its name, change BINARY_NAME above,
# not the value here, or `flutter run` will no longer work. # not the value here, or `flutter run` will no longer work.
# #
# Any new source files that you add to the application should be added here. # Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME} add_executable(${BINARY_NAME}
"main.cc" "main.cc"
"my_application.cc" "my_application.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
) )
# Apply the standard set of build settings. This can be removed for applications # Apply the standard set of build settings. This can be removed for applications
# that need different build settings. # that need different build settings.
apply_standard_settings(${BINARY_NAME}) apply_standard_settings(${BINARY_NAME})
# Add dependency libraries. Add any application-specific dependencies here. # Add dependency libraries. Add any application-specific dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter) target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
# Run the Flutter tool portions of the build. This must not be removed. # Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble) add_dependencies(${BINARY_NAME} flutter_assemble)
# Only the install-generated bundle's copy of the executable will launch # Only the install-generated bundle's copy of the executable will launch
# correctly, since the resources must in the right relative locations. To avoid # correctly, since the resources must in the right relative locations. To avoid
# people trying to run the unbundled copy, put it in a subdirectory instead of # people trying to run the unbundled copy, put it in a subdirectory instead of
# the default top-level location. # the default top-level location.
set_target_properties(${BINARY_NAME} set_target_properties(${BINARY_NAME}
PROPERTIES PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
) )
# Generated plugin build rules, which manage building the plugins and adding # Generated plugin build rules, which manage building the plugins and adding
# them to the application. # them to the application.
include(flutter/generated_plugins.cmake) include(flutter/generated_plugins.cmake)
# === Installation === # === Installation ===
# By default, "installing" just makes a relocatable bundle in the build # By default, "installing" just makes a relocatable bundle in the build
# directory. # directory.
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif() endif()
# Start with a clean build bundle directory every time. # Start with a clean build bundle directory every time.
install(CODE " install(CODE "
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
" COMPONENT Runtime) " COMPONENT Runtime)
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime) COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime) COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime) COMPONENT Runtime)
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
install(FILES "${bundled_library}" install(FILES "${bundled_library}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime) COMPONENT Runtime)
endforeach(bundled_library) endforeach(bundled_library)
# add app icon # add app icon
install(FILES "app_icon.ico" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}") install(FILES "app_icon.ico" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}")
# Fully re-copy the assets directory on each build to avoid having stale files # Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install. # from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets") set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE " install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime) " COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only. # Install the AOT library on non-Debug builds only.
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime) COMPONENT Runtime)
endif() endif()

View File

@ -1,88 +1,88 @@
# This file controls Flutter-level build steps. It should not be edited. # This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool. # Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake) include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See # TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146. # https://github.com/flutter/flutter/issues/57146.
# Serves the same purpose as list(TRANSFORM ... PREPEND ...), # Serves the same purpose as list(TRANSFORM ... PREPEND ...),
# which isn't available in 3.10. # which isn't available in 3.10.
function(list_prepend LIST_NAME PREFIX) function(list_prepend LIST_NAME PREFIX)
set(NEW_LIST "") set(NEW_LIST "")
foreach(element ${${LIST_NAME}}) foreach(element ${${LIST_NAME}})
list(APPEND NEW_LIST "${PREFIX}${element}") list(APPEND NEW_LIST "${PREFIX}${element}")
endforeach(element) endforeach(element)
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
endfunction() endfunction()
# === Flutter Library === # === Flutter Library ===
# System-level dependencies. # System-level dependencies.
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
# Published to parent scope for install step. # Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS list(APPEND FLUTTER_LIBRARY_HEADERS
"fl_basic_message_channel.h" "fl_basic_message_channel.h"
"fl_binary_codec.h" "fl_binary_codec.h"
"fl_binary_messenger.h" "fl_binary_messenger.h"
"fl_dart_project.h" "fl_dart_project.h"
"fl_engine.h" "fl_engine.h"
"fl_json_message_codec.h" "fl_json_message_codec.h"
"fl_json_method_codec.h" "fl_json_method_codec.h"
"fl_message_codec.h" "fl_message_codec.h"
"fl_method_call.h" "fl_method_call.h"
"fl_method_channel.h" "fl_method_channel.h"
"fl_method_codec.h" "fl_method_codec.h"
"fl_method_response.h" "fl_method_response.h"
"fl_plugin_registrar.h" "fl_plugin_registrar.h"
"fl_plugin_registry.h" "fl_plugin_registry.h"
"fl_standard_message_codec.h" "fl_standard_message_codec.h"
"fl_standard_method_codec.h" "fl_standard_method_codec.h"
"fl_string_codec.h" "fl_string_codec.h"
"fl_value.h" "fl_value.h"
"fl_view.h" "fl_view.h"
"flutter_linux.h" "flutter_linux.h"
) )
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
add_library(flutter INTERFACE) add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}" "${EPHEMERAL_DIR}"
) )
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
target_link_libraries(flutter INTERFACE target_link_libraries(flutter INTERFACE
PkgConfig::GTK PkgConfig::GTK
PkgConfig::GLIB PkgConfig::GLIB
PkgConfig::GIO PkgConfig::GIO
) )
add_dependencies(flutter flutter_assemble) add_dependencies(flutter flutter_assemble)
# === Flutter tool backend === # === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time, # _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the # since currently there's no way to get a full input/output list from the
# flutter tool. # flutter tool.
add_custom_command( add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/_phony_ ${CMAKE_CURRENT_BINARY_DIR}/_phony_
COMMAND ${CMAKE_COMMAND} -E env COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT} ${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
VERBATIM VERBATIM
) )
add_custom_target(flutter_assemble DEPENDS add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}" "${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS} ${FLUTTER_LIBRARY_HEADERS}
) )

View File

@ -1,6 +1,6 @@
#include "my_application.h" #include "my_application.h"
int main(int argc, char** argv) { int main(int argc, char** argv) {
g_autoptr(MyApplication) app = my_application_new(); g_autoptr(MyApplication) app = my_application_new();
return g_application_run(G_APPLICATION(app), argc, argv); return g_application_run(G_APPLICATION(app), argc, argv);
} }

View File

@ -1,118 +1,118 @@
#include "my_application.h" #include "my_application.h"
#include <flutter_linux/flutter_linux.h> #include <flutter_linux/flutter_linux.h>
#ifdef GDK_WINDOWING_X11 #ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h> #include <gdk/gdkx.h>
#endif #endif
#include "flutter/generated_plugin_registrant.h" #include "flutter/generated_plugin_registrant.h"
struct _MyApplication struct _MyApplication
{ {
GtkApplication parent_instance; GtkApplication parent_instance;
char **dart_entrypoint_arguments; char **dart_entrypoint_arguments;
}; };
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
// Implements GApplication::activate. // Implements GApplication::activate.
static void my_application_activate(GApplication *application) static void my_application_activate(GApplication *application)
{ {
MyApplication *self = MY_APPLICATION(application); MyApplication *self = MY_APPLICATION(application);
GtkWindow *window = GtkWindow *window =
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
// Use a header bar when running in GNOME as this is the common style used // Use a header bar when running in GNOME as this is the common style used
// by applications and is the setup most users will be using (e.g. Ubuntu // by applications and is the setup most users will be using (e.g. Ubuntu
// desktop). // desktop).
// If running on X and not using GNOME then just use a traditional title bar // If running on X and not using GNOME then just use a traditional title bar
// in case the window manager does more exotic layout, e.g. tiling. // in case the window manager does more exotic layout, e.g. tiling.
// If running on Wayland assume the header bar will work (may need changing // If running on Wayland assume the header bar will work (may need changing
// if future cases occur). // if future cases occur).
gboolean use_header_bar = TRUE; gboolean use_header_bar = TRUE;
#ifdef GDK_WINDOWING_X11 #ifdef GDK_WINDOWING_X11
GdkScreen *screen = gtk_window_get_screen(window); GdkScreen *screen = gtk_window_get_screen(window);
if (GDK_IS_X11_SCREEN(screen)) if (GDK_IS_X11_SCREEN(screen))
{ {
const gchar *wm_name = gdk_x11_screen_get_window_manager_name(screen); const gchar *wm_name = gdk_x11_screen_get_window_manager_name(screen);
if (g_strcmp0(wm_name, "GNOME Shell") != 0) if (g_strcmp0(wm_name, "GNOME Shell") != 0)
{ {
use_header_bar = FALSE; use_header_bar = FALSE;
} }
} }
#endif #endif
// set icon // set icon
gtk_window_set_icon_from_file(window, "data/app_icon.ico", NULL); gtk_window_set_icon_from_file(window, "data/app_icon.ico", NULL);
if (use_header_bar) if (use_header_bar)
{ {
GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar)); gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "Freezer"); gtk_header_bar_set_title(header_bar, "Freezer");
gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
} }
else else
{ {
gtk_window_set_title(window, "Freezer"); gtk_window_set_title(window, "Freezer");
} }
gtk_window_set_default_size(window, 1280, 720); gtk_window_set_default_size(window, 1280, 720);
gtk_widget_show(GTK_WIDGET(window)); gtk_widget_show(GTK_WIDGET(window));
g_autoptr(FlDartProject) project = fl_dart_project_new(); g_autoptr(FlDartProject) project = fl_dart_project_new();
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
FlView *view = fl_view_new(project); FlView *view = fl_view_new(project);
gtk_widget_show(GTK_WIDGET(view)); gtk_widget_show(GTK_WIDGET(view));
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
fl_register_plugins(FL_PLUGIN_REGISTRY(view)); fl_register_plugins(FL_PLUGIN_REGISTRY(view));
gtk_widget_grab_focus(GTK_WIDGET(view)); gtk_widget_grab_focus(GTK_WIDGET(view));
} }
// Implements GApplication::local_command_line. // Implements GApplication::local_command_line.
static gboolean my_application_local_command_line(GApplication *application, gchar ***arguments, int *exit_status) static gboolean my_application_local_command_line(GApplication *application, gchar ***arguments, int *exit_status)
{ {
MyApplication *self = MY_APPLICATION(application); MyApplication *self = MY_APPLICATION(application);
// Strip out the first argument as it is the binary name. // Strip out the first argument as it is the binary name.
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
g_autoptr(GError) error = nullptr; g_autoptr(GError) error = nullptr;
if (!g_application_register(application, nullptr, &error)) if (!g_application_register(application, nullptr, &error))
{ {
g_warning("Failed to register: %s", error->message); g_warning("Failed to register: %s", error->message);
*exit_status = 1; *exit_status = 1;
return TRUE; return TRUE;
} }
g_application_activate(application); g_application_activate(application);
*exit_status = 0; *exit_status = 0;
return TRUE; return TRUE;
} }
// Implements GObject::dispose. // Implements GObject::dispose.
static void my_application_dispose(GObject *object) static void my_application_dispose(GObject *object)
{ {
MyApplication *self = MY_APPLICATION(object); MyApplication *self = MY_APPLICATION(object);
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
G_OBJECT_CLASS(my_application_parent_class)->dispose(object); G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
} }
static void my_application_class_init(MyApplicationClass *klass) static void my_application_class_init(MyApplicationClass *klass)
{ {
G_APPLICATION_CLASS(klass)->activate = my_application_activate; G_APPLICATION_CLASS(klass)->activate = my_application_activate;
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
G_OBJECT_CLASS(klass)->dispose = my_application_dispose; G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
} }
static void my_application_init(MyApplication *self) {} static void my_application_init(MyApplication *self) {}
MyApplication *my_application_new() MyApplication *my_application_new()
{ {
return MY_APPLICATION(g_object_new(my_application_get_type(), return MY_APPLICATION(g_object_new(my_application_get_type(),
"application-id", APPLICATION_ID, "application-id", APPLICATION_ID,
"flags", G_APPLICATION_NON_UNIQUE, "flags", G_APPLICATION_NON_UNIQUE,
nullptr)); nullptr));
} }

View File

@ -1,18 +1,18 @@
#ifndef FLUTTER_MY_APPLICATION_H_ #ifndef FLUTTER_MY_APPLICATION_H_
#define FLUTTER_MY_APPLICATION_H_ #define FLUTTER_MY_APPLICATION_H_
#include <gtk/gtk.h> #include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
GtkApplication) GtkApplication)
/** /**
* my_application_new: * my_application_new:
* *
* Creates a new Flutter-based application. * Creates a new Flutter-based application.
* *
* Returns: a new #MyApplication. * Returns: a new #MyApplication.
*/ */
MyApplication* my_application_new(); MyApplication* my_application_new();
#endif // FLUTTER_MY_APPLICATION_H_ #endif // FLUTTER_MY_APPLICATION_H_

14
macos/.gitignore vendored
View File

@ -1,7 +1,7 @@
# Flutter-related # Flutter-related
**/Flutter/ephemeral/ **/Flutter/ephemeral/
**/Pods/ **/Pods/
# Xcode-related # Xcode-related
**/dgph **/dgph
**/xcuserdata/ **/xcuserdata/

View File

@ -1 +1 @@
#include "ephemeral/Flutter-Generated.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig"

View File

@ -1 +1 @@
#include "ephemeral/Flutter-Generated.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig"

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>IDEDidComputeMac32BitWarning</key> <key>IDEDidComputeMac32BitWarning</key>
<true/> <true/>
</dict> </dict>
</plist> </plist>

View File

@ -1,98 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1300" LastUpgradeVersion = "1430"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"> buildImplicitDependencies = "YES">
<BuildActionEntries> <BuildActionEntries>
<BuildActionEntry <BuildActionEntry
buildForTesting = "YES" buildForTesting = "YES"
buildForRunning = "YES" buildForRunning = "YES"
buildForProfiling = "YES" buildForProfiling = "YES"
buildForArchiving = "YES" buildForArchiving = "YES"
buildForAnalyzing = "YES"> buildForAnalyzing = "YES">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045" BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "freezer.app" BuildableName = "freezer.app"
BlueprintName = "Runner" BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion> <MacroExpansion>
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045" BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "freezer.app" BuildableName = "freezer.app"
BlueprintName = "Runner" BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<Testables> <Testables>
<TestableReference <TestableReference
skipped = "NO" skipped = "NO"
parallelizable = "YES"> parallelizable = "YES">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "331C80D4294CF70F00263BE5" BlueprintIdentifier = "331C80D4294CF70F00263BE5"
BuildableName = "RunnerTests.xctest" BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests" BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
</Testables> </Testables>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045" BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "freezer.app" BuildableName = "freezer.app"
BlueprintName = "Runner" BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Profile" buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = "" savedToolIdentifier = ""
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"> debugDocumentVersioning = "YES">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045" BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "freezer.app" BuildableName = "freezer.app"
BlueprintName = "Runner" BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</ProfileAction> </ProfileAction>
<AnalyzeAction <AnalyzeAction
buildConfiguration = "Debug"> buildConfiguration = "Debug">
</AnalyzeAction> </AnalyzeAction>
<ArchiveAction <ArchiveAction
buildConfiguration = "Release" buildConfiguration = "Release"
revealArchiveInOrganizer = "YES"> revealArchiveInOrganizer = "YES">
</ArchiveAction> </ArchiveAction>
</Scheme> </Scheme>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Workspace <Workspace
version = "1.0"> version = "1.0">
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "group:Runner.xcodeproj">
</FileRef> </FileRef>
</Workspace> </Workspace>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>IDEDidComputeMac32BitWarning</key> <key>IDEDidComputeMac32BitWarning</key>
<true/> <true/>
</dict> </dict>
</plist> </plist>

View File

@ -1,9 +1,9 @@
import Cocoa import Cocoa
import FlutterMacOS import FlutterMacOS
@NSApplicationMain @NSApplicationMain
class AppDelegate: FlutterAppDelegate { class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true return true
} }
} }

View File

@ -1,68 +1,68 @@
{ {
"images" : [ "images" : [
{ {
"size" : "16x16", "size" : "16x16",
"idiom" : "mac", "idiom" : "mac",
"filename" : "app_icon_16.png", "filename" : "app_icon_16.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "16x16", "size" : "16x16",
"idiom" : "mac", "idiom" : "mac",
"filename" : "app_icon_32.png", "filename" : "app_icon_32.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "32x32", "size" : "32x32",
"idiom" : "mac", "idiom" : "mac",
"filename" : "app_icon_32.png", "filename" : "app_icon_32.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "32x32", "size" : "32x32",
"idiom" : "mac", "idiom" : "mac",
"filename" : "app_icon_64.png", "filename" : "app_icon_64.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "128x128", "size" : "128x128",
"idiom" : "mac", "idiom" : "mac",
"filename" : "app_icon_128.png", "filename" : "app_icon_128.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "128x128", "size" : "128x128",
"idiom" : "mac", "idiom" : "mac",
"filename" : "app_icon_256.png", "filename" : "app_icon_256.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "256x256", "size" : "256x256",
"idiom" : "mac", "idiom" : "mac",
"filename" : "app_icon_256.png", "filename" : "app_icon_256.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "256x256", "size" : "256x256",
"idiom" : "mac", "idiom" : "mac",
"filename" : "app_icon_512.png", "filename" : "app_icon_512.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "512x512", "size" : "512x512",
"idiom" : "mac", "idiom" : "mac",
"filename" : "app_icon_512.png", "filename" : "app_icon_512.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "512x512", "size" : "512x512",
"idiom" : "mac", "idiom" : "mac",
"filename" : "app_icon_1024.png", "filename" : "app_icon_1024.png",
"scale" : "2x" "scale" : "2x"
} }
], ],
"info" : { "info" : {
"version" : 1, "version" : 1,
"author" : "xcode" "author" : "xcode"
} }
} }

View File

@ -1,343 +1,343 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies> <dependencies>
<deployment identifier="macosx"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<objects> <objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication"> <customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections> <connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/> <outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections> </connections>
</customObject> </customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/> <customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target"> <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target">
<connections> <connections>
<outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/> <outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
<outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/> <outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections> </connections>
</customObject> </customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/> <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6"> <menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items> <items>
<menuItem title="APP_NAME" id="1Xt-HY-uBw"> <menuItem title="APP_NAME" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr"> <menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
<items> <items>
<menuItem title="About APP_NAME" id="5kV-Vb-QxS"> <menuItem title="About APP_NAME" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/> <action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/> <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/> <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/> <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz"> <menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/> <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/> <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN"> <menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
<connections> <connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/> <action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO"> <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections> <connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/> <action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS"> <menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/> <action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/> <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi"> <menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
<connections> <connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/> <action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections> </connections>
</menuItem> </menuItem>
</items> </items>
</menu> </menu>
</menuItem> </menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T"> <menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl"> <menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items> <items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg"> <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections> <connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/> <action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam"> <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections> <connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/> <action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/> <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG"> <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections> <connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/> <action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU"> <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections> <connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/> <action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL"> <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections> <connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/> <action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk"> <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections> <connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/> <action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Delete" id="pa3-QI-u2k"> <menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/> <action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m"> <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections> <connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/> <action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/> <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u"> <menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx"> <menu key="submenu" title="Find" id="1b7-l0-nxx">
<items> <items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W"> <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections> <connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/> <action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz"> <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections> <connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/> <action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye"> <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections> <connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/> <action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV"> <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections> <connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/> <action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt"> <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections> <connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/> <action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd"> <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections> <connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/> <action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections> </connections>
</menuItem> </menuItem>
</items> </items>
</menu> </menu>
</menuItem> </menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7"> <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg"> <menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items> <items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI"> <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections> <connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/> <action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7"> <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections> <connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/> <action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/> <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN"> <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/> <action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG"> <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/> <action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v"> <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/> <action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections> </connections>
</menuItem> </menuItem>
</items> </items>
</menu> </menu>
</menuItem> </menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx"> <menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr"> <menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items> <items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz"> <menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/> <action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/> <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM"> <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/> <action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv"> <menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/> <action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn"> <menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/> <action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid"> <menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/> <action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS"> <menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/> <action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA"> <menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/> <action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections> </connections>
</menuItem> </menuItem>
</items> </items>
</menu> </menu>
</menuItem> </menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC"> <menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd"> <menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items> <items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI"> <menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/> <action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd"> <menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/> <action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG"> <menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/> <action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections> </connections>
</menuItem> </menuItem>
</items> </items>
</menu> </menu>
</menuItem> </menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0"> <menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH"> <menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items> <items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ"> <menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/> <action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm"> <menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/> <action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections> </connections>
</menuItem> </menuItem>
</items> </items>
</menu> </menu>
</menuItem> </menuItem>
</items> </items>
</menu> </menu>
</menuItem> </menuItem>
<menuItem title="View" id="H8h-7b-M4v"> <menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO"> <menu key="submenu" title="View" id="HyV-fh-RgO">
<items> <items>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa"> <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections> <connections>
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/> <action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
</connections> </connections>
</menuItem> </menuItem>
</items> </items>
</menu> </menu>
</menuItem> </menuItem>
<menuItem title="Window" id="aUF-d1-5bR"> <menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo"> <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items> <items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV"> <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections> <connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/> <action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4"> <menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/> <action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/> <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ"> <menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/> <action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections> </connections>
</menuItem> </menuItem>
</items> </items>
</menu> </menu>
</menuItem> </menuItem>
<menuItem title="Help" id="EPT-qC-fAb"> <menuItem title="Help" id="EPT-qC-fAb">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/> <menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/>
</menuItem> </menuItem>
</items> </items>
<point key="canvasLocation" x="142" y="-258"/> <point key="canvasLocation" x="142" y="-258"/>
</menu> </menu>
<window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target"> <window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="335" y="390" width="800" height="600"/> <rect key="contentRect" x="335" y="390" width="800" height="600"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/> <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ"> <view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/> <rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
</view> </view>
</window> </window>
</objects> </objects>
</document> </document>

View File

@ -1,14 +1,14 @@
// Application-level settings for the Runner target. // Application-level settings for the Runner target.
// //
// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
// future. If not, the values below would default to using the project name when this becomes a // future. If not, the values below would default to using the project name when this becomes a
// 'flutter create' template. // 'flutter create' template.
// The application's name. By default this is also the title of the Flutter window. // The application's name. By default this is also the title of the Flutter window.
PRODUCT_NAME = freezer PRODUCT_NAME = freezer
// The application's bundle identifier // The application's bundle identifier
PRODUCT_BUNDLE_IDENTIFIER = f.f.freezer PRODUCT_BUNDLE_IDENTIFIER = f.f.freezer
// The copyright displayed in application information // The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2023 f.f. All rights reserved. PRODUCT_COPYRIGHT = Copyright © 2023 f.f. All rights reserved.

View File

@ -1,2 +1,2 @@
#include "../../Flutter/Flutter-Debug.xcconfig" #include "../../Flutter/Flutter-Debug.xcconfig"
#include "Warnings.xcconfig" #include "Warnings.xcconfig"

View File

@ -1,2 +1,2 @@
#include "../../Flutter/Flutter-Release.xcconfig" #include "../../Flutter/Flutter-Release.xcconfig"
#include "Warnings.xcconfig" #include "Warnings.xcconfig"

View File

@ -1,13 +1,13 @@
WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
GCC_WARN_UNDECLARED_SELECTOR = YES GCC_WARN_UNDECLARED_SELECTOR = YES
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
CLANG_WARN_PRAGMA_PACK = YES CLANG_WARN_PRAGMA_PACK = YES
CLANG_WARN_STRICT_PROTOTYPES = YES CLANG_WARN_STRICT_PROTOTYPES = YES
CLANG_WARN_COMMA = YES CLANG_WARN_COMMA = YES
GCC_WARN_STRICT_SELECTOR_MATCH = YES GCC_WARN_STRICT_SELECTOR_MATCH = YES
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
GCC_WARN_SHADOW = YES GCC_WARN_SHADOW = YES
CLANG_WARN_UNREACHABLE_CODE = YES CLANG_WARN_UNREACHABLE_CODE = YES

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>com.apple.security.app-sandbox</key> <key>com.apple.security.app-sandbox</key>
<true/> <true/>
<key>com.apple.security.cs.allow-jit</key> <key>com.apple.security.cs.allow-jit</key>
<true/> <true/>
<key>com.apple.security.network.server</key> <key>com.apple.security.network.server</key>
<true/> <true/>
</dict> </dict>
</plist> </plist>

View File

@ -1,32 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string></string> <string></string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string> <string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string> <string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string> <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_COPYRIGHT)</string> <string>$(PRODUCT_COPYRIGHT)</string>
<key>NSMainNibFile</key> <key>NSMainNibFile</key>
<string>MainMenu</string> <string>MainMenu</string>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>
<string>NSApplication</string> <string>NSApplication</string>
</dict> </dict>
</plist> </plist>

View File

@ -1,15 +1,15 @@
import Cocoa import Cocoa
import FlutterMacOS import FlutterMacOS
class MainFlutterWindow: NSWindow { class MainFlutterWindow: NSWindow {
override func awakeFromNib() { override func awakeFromNib() {
let flutterViewController = FlutterViewController() let flutterViewController = FlutterViewController()
let windowFrame = self.frame let windowFrame = self.frame
self.contentViewController = flutterViewController self.contentViewController = flutterViewController
self.setFrame(windowFrame, display: true) self.setFrame(windowFrame, display: true)
RegisterGeneratedPlugins(registry: flutterViewController) RegisterGeneratedPlugins(registry: flutterViewController)
super.awakeFromNib() super.awakeFromNib()
} }
} }

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>com.apple.security.app-sandbox</key> <key>com.apple.security.app-sandbox</key>
<true/> <true/>
</dict> </dict>
</plist> </plist>

View File

@ -1,12 +1,12 @@
import FlutterMacOS import FlutterMacOS
import Cocoa import Cocoa
import XCTest import XCTest
class RunnerTests: XCTestCase { class RunnerTests: XCTestCase {
func testExample() { func testExample() {
// If you add code to the Runner application, consider adding tests here. // If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest. // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
} }
} }

File diff suppressed because it is too large Load Diff

34
windows/.gitignore vendored
View File

@ -1,17 +1,17 @@
flutter/ephemeral/ flutter/ephemeral/
# Visual Studio user-specific files. # Visual Studio user-specific files.
*.suo *.suo
*.user *.user
*.userosscache *.userosscache
*.sln.docstates *.sln.docstates
# Visual Studio build-related files. # Visual Studio build-related files.
x64/ x64/
x86/ x86/
# Visual Studio cache files # Visual Studio cache files
# files ending in .cache can be ignored # files ending in .cache can be ignored
*.[Cc]ache *.[Cc]ache
# but keep track of directories ending in .cache # but keep track of directories ending in .cache
!*.[Cc]ache/ !*.[Cc]ache/

View File

@ -1,102 +1,102 @@
# Project-level configuration. # Project-level configuration.
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
project(freezer LANGUAGES CXX) project(freezer LANGUAGES CXX)
# The name of the executable created for the application. Change this to change # The name of the executable created for the application. Change this to change
# the on-disk name of your application. # the on-disk name of your application.
set(BINARY_NAME "freezer") set(BINARY_NAME "freezer")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent # Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake. # versions of CMake.
cmake_policy(SET CMP0063 NEW) cmake_policy(VERSION 3.14...3.25)
# Define build configuration option. # Define build configuration option.
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(IS_MULTICONFIG) if(IS_MULTICONFIG)
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
CACHE STRING "" FORCE) CACHE STRING "" FORCE)
else() else()
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE) STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release") "Debug" "Profile" "Release")
endif() endif()
endif() endif()
# Define settings for the Profile build mode. # Define settings for the Profile build mode.
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
# Use Unicode for all projects. # Use Unicode for all projects.
add_definitions(-DUNICODE -D_UNICODE) add_definitions(-DUNICODE -D_UNICODE)
# Compilation settings that should be applied to most targets. # Compilation settings that should be applied to most targets.
# #
# Be cautious about adding new options here, as plugins use this function by # Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead # default. In most cases, you should add new options to specific targets instead
# of modifying this function. # of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET) function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_features(${TARGET} PUBLIC cxx_std_17)
target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
target_compile_options(${TARGET} PRIVATE /EHsc) target_compile_options(${TARGET} PRIVATE /EHsc)
target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>") target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
endfunction() endfunction()
# Flutter library and tool build rules. # Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR}) add_subdirectory(${FLUTTER_MANAGED_DIR})
# Application build; see runner/CMakeLists.txt. # Application build; see runner/CMakeLists.txt.
add_subdirectory("runner") add_subdirectory("runner")
# Generated plugin build rules, which manage building the plugins and adding # Generated plugin build rules, which manage building the plugins and adding
# them to the application. # them to the application.
include(flutter/generated_plugins.cmake) include(flutter/generated_plugins.cmake)
# === Installation === # === Installation ===
# Support files are copied into place next to the executable, so that it can # Support files are copied into place next to the executable, so that it can
# run in place. This is done instead of making a separate bundle (as on Linux) # run in place. This is done instead of making a separate bundle (as on Linux)
# so that building and running from within Visual Studio will work. # so that building and running from within Visual Studio will work.
set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>") set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
# Make the "install" step default, as it's required to run. # Make the "install" step default, as it's required to run.
set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif() endif()
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime) COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime) COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime) COMPONENT Runtime)
if(PLUGIN_BUNDLED_LIBRARIES) if(PLUGIN_BUNDLED_LIBRARIES)
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime) COMPONENT Runtime)
endif() endif()
# Fully re-copy the assets directory on each build to avoid having stale files # Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install. # from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets") set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE " install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime) " COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only. # Install the AOT library on non-Debug builds only.
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
CONFIGURATIONS Profile;Release CONFIGURATIONS Profile;Release
COMPONENT Runtime) COMPONENT Runtime)

View File

@ -1,104 +1,104 @@
# This file controls Flutter-level build steps. It should not be edited. # This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool. # Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake) include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See # TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146. # https://github.com/flutter/flutter/issues/57146.
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
# === Flutter Library === # === Flutter Library ===
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
# Published to parent scope for install step. # Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS list(APPEND FLUTTER_LIBRARY_HEADERS
"flutter_export.h" "flutter_export.h"
"flutter_windows.h" "flutter_windows.h"
"flutter_messenger.h" "flutter_messenger.h"
"flutter_plugin_registrar.h" "flutter_plugin_registrar.h"
"flutter_texture_registrar.h" "flutter_texture_registrar.h"
) )
list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
add_library(flutter INTERFACE) add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}" "${EPHEMERAL_DIR}"
) )
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
add_dependencies(flutter flutter_assemble) add_dependencies(flutter flutter_assemble)
# === Wrapper === # === Wrapper ===
list(APPEND CPP_WRAPPER_SOURCES_CORE list(APPEND CPP_WRAPPER_SOURCES_CORE
"core_implementations.cc" "core_implementations.cc"
"standard_codec.cc" "standard_codec.cc"
) )
list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_PLUGIN list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
"plugin_registrar.cc" "plugin_registrar.cc"
) )
list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_APP list(APPEND CPP_WRAPPER_SOURCES_APP
"flutter_engine.cc" "flutter_engine.cc"
"flutter_view_controller.cc" "flutter_view_controller.cc"
) )
list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
# Wrapper sources needed for a plugin. # Wrapper sources needed for a plugin.
add_library(flutter_wrapper_plugin STATIC add_library(flutter_wrapper_plugin STATIC
${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_PLUGIN}
) )
apply_standard_settings(flutter_wrapper_plugin) apply_standard_settings(flutter_wrapper_plugin)
set_target_properties(flutter_wrapper_plugin PROPERTIES set_target_properties(flutter_wrapper_plugin PROPERTIES
POSITION_INDEPENDENT_CODE ON) POSITION_INDEPENDENT_CODE ON)
set_target_properties(flutter_wrapper_plugin PROPERTIES set_target_properties(flutter_wrapper_plugin PROPERTIES
CXX_VISIBILITY_PRESET hidden) CXX_VISIBILITY_PRESET hidden)
target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
target_include_directories(flutter_wrapper_plugin PUBLIC target_include_directories(flutter_wrapper_plugin PUBLIC
"${WRAPPER_ROOT}/include" "${WRAPPER_ROOT}/include"
) )
add_dependencies(flutter_wrapper_plugin flutter_assemble) add_dependencies(flutter_wrapper_plugin flutter_assemble)
# Wrapper sources needed for the runner. # Wrapper sources needed for the runner.
add_library(flutter_wrapper_app STATIC add_library(flutter_wrapper_app STATIC
${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_APP} ${CPP_WRAPPER_SOURCES_APP}
) )
apply_standard_settings(flutter_wrapper_app) apply_standard_settings(flutter_wrapper_app)
target_link_libraries(flutter_wrapper_app PUBLIC flutter) target_link_libraries(flutter_wrapper_app PUBLIC flutter)
target_include_directories(flutter_wrapper_app PUBLIC target_include_directories(flutter_wrapper_app PUBLIC
"${WRAPPER_ROOT}/include" "${WRAPPER_ROOT}/include"
) )
add_dependencies(flutter_wrapper_app flutter_assemble) add_dependencies(flutter_wrapper_app flutter_assemble)
# === Flutter tool backend === # === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time, # _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the # since currently there's no way to get a full input/output list from the
# flutter tool. # flutter tool.
set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
add_custom_command( add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP} ${CPP_WRAPPER_SOURCES_APP}
${PHONY_OUTPUT} ${PHONY_OUTPUT}
COMMAND ${CMAKE_COMMAND} -E env COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT} ${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
windows-x64 $<CONFIG> windows-x64 $<CONFIG>
VERBATIM VERBATIM
) )
add_custom_target(flutter_assemble DEPENDS add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}" "${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS} ${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP} ${CPP_WRAPPER_SOURCES_APP}
) )

View File

@ -1,40 +1,40 @@
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
project(runner LANGUAGES CXX) project(runner LANGUAGES CXX)
# Define the application target. To change its name, change BINARY_NAME in the # Define the application target. To change its name, change BINARY_NAME in the
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
# work. # work.
# #
# Any new source files that you add to the application should be added here. # Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME} WIN32 add_executable(${BINARY_NAME} WIN32
"flutter_window.cpp" "flutter_window.cpp"
"main.cpp" "main.cpp"
"utils.cpp" "utils.cpp"
"win32_window.cpp" "win32_window.cpp"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
"Runner.rc" "Runner.rc"
"runner.exe.manifest" "runner.exe.manifest"
) )
# Apply the standard set of build settings. This can be removed for applications # Apply the standard set of build settings. This can be removed for applications
# that need different build settings. # that need different build settings.
apply_standard_settings(${BINARY_NAME}) apply_standard_settings(${BINARY_NAME})
# Add preprocessor definitions for the build version. # Add preprocessor definitions for the build version.
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
# Disable Windows macros that collide with C++ standard library functions. # Disable Windows macros that collide with C++ standard library functions.
target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
# Add dependency libraries and include directories. Add any application-specific # Add dependency libraries and include directories. Add any application-specific
# dependencies here. # dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
# Run the Flutter tool portions of the build. This must not be removed. # Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble) add_dependencies(${BINARY_NAME} flutter_assemble)

View File

@ -1,121 +1,121 @@
// Microsoft Visual C++ generated resource script. // Microsoft Visual C++ generated resource script.
// //
#pragma code_page(65001) #pragma code_page(65001)
#include "resource.h" #include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS #define APSTUDIO_READONLY_SYMBOLS
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
// Generated from the TEXTINCLUDE 2 resource. // Generated from the TEXTINCLUDE 2 resource.
// //
#include "winres.h" #include "winres.h"
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS #undef APSTUDIO_READONLY_SYMBOLS
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// English (United States) resources // English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
// TEXTINCLUDE // TEXTINCLUDE
// //
1 TEXTINCLUDE 1 TEXTINCLUDE
BEGIN BEGIN
"resource.h\0" "resource.h\0"
END END
2 TEXTINCLUDE 2 TEXTINCLUDE
BEGIN BEGIN
"#include ""winres.h""\r\n" "#include ""winres.h""\r\n"
"\0" "\0"
END END
3 TEXTINCLUDE 3 TEXTINCLUDE
BEGIN BEGIN
"\r\n" "\r\n"
"\0" "\0"
END END
#endif // APSTUDIO_INVOKED #endif // APSTUDIO_INVOKED
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
// Icon // Icon
// //
// Icon with lowest ID value placed first to ensure application icon // Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems. // remains consistent on all systems.
IDI_APP_ICON ICON "resources\\app_icon.ico" IDI_APP_ICON ICON "resources\\app_icon.ico"
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
// Version // Version
// //
#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
#else #else
#define VERSION_AS_NUMBER 1,0,0,0 #define VERSION_AS_NUMBER 1,0,0,0
#endif #endif
#if defined(FLUTTER_VERSION) #if defined(FLUTTER_VERSION)
#define VERSION_AS_STRING FLUTTER_VERSION #define VERSION_AS_STRING FLUTTER_VERSION
#else #else
#define VERSION_AS_STRING "1.0.0" #define VERSION_AS_STRING "1.0.0"
#endif #endif
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_AS_NUMBER FILEVERSION VERSION_AS_NUMBER
PRODUCTVERSION VERSION_AS_NUMBER PRODUCTVERSION VERSION_AS_NUMBER
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG FILEFLAGS VS_FF_DEBUG
#else #else
FILEFLAGS 0x0L FILEFLAGS 0x0L
#endif #endif
FILEOS VOS__WINDOWS32 FILEOS VOS__WINDOWS32
FILETYPE VFT_APP FILETYPE VFT_APP
FILESUBTYPE 0x0L FILESUBTYPE 0x0L
BEGIN BEGIN
BLOCK "StringFileInfo" BLOCK "StringFileInfo"
BEGIN BEGIN
BLOCK "040904e4" BLOCK "040904e4"
BEGIN BEGIN
VALUE "CompanyName", "f.f" "\0" VALUE "CompanyName", "f.f" "\0"
VALUE "FileDescription", "freezer" "\0" VALUE "FileDescription", "freezer" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "freezer" "\0" VALUE "InternalName", "freezer" "\0"
VALUE "LegalCopyright", "Copyright (C) 2023 f.f. All rights reserved." "\0" VALUE "LegalCopyright", "Copyright (C) 2023 f.f. All rights reserved." "\0"
VALUE "OriginalFilename", "freezer.exe" "\0" VALUE "OriginalFilename", "freezer.exe" "\0"
VALUE "ProductName", "freezer" "\0" VALUE "ProductName", "freezer" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
BEGIN BEGIN
VALUE "Translation", 0x409, 1252 VALUE "Translation", 0x409, 1252
END END
END END
#endif // English (United States) resources #endif // English (United States) resources
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED #ifndef APSTUDIO_INVOKED
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
// Generated from the TEXTINCLUDE 3 resource. // Generated from the TEXTINCLUDE 3 resource.
// //
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED #endif // not APSTUDIO_INVOKED

View File

@ -1,66 +1,71 @@
#include "flutter_window.h" #include "flutter_window.h"
#include <optional> #include <optional>
#include "flutter/generated_plugin_registrant.h" #include "flutter/generated_plugin_registrant.h"
FlutterWindow::FlutterWindow(const flutter::DartProject& project) FlutterWindow::FlutterWindow(const flutter::DartProject& project)
: project_(project) {} : project_(project) {}
FlutterWindow::~FlutterWindow() {} FlutterWindow::~FlutterWindow() {}
bool FlutterWindow::OnCreate() { bool FlutterWindow::OnCreate() {
if (!Win32Window::OnCreate()) { if (!Win32Window::OnCreate()) {
return false; return false;
} }
RECT frame = GetClientArea(); RECT frame = GetClientArea();
// The size here must match the window dimensions to avoid unnecessary surface // The size here must match the window dimensions to avoid unnecessary surface
// creation / destruction in the startup path. // creation / destruction in the startup path.
flutter_controller_ = std::make_unique<flutter::FlutterViewController>( flutter_controller_ = std::make_unique<flutter::FlutterViewController>(
frame.right - frame.left, frame.bottom - frame.top, project_); frame.right - frame.left, frame.bottom - frame.top, project_);
// Ensure that basic setup of the controller was successful. // Ensure that basic setup of the controller was successful.
if (!flutter_controller_->engine() || !flutter_controller_->view()) { if (!flutter_controller_->engine() || !flutter_controller_->view()) {
return false; return false;
} }
RegisterPlugins(flutter_controller_->engine()); RegisterPlugins(flutter_controller_->engine());
SetChildContent(flutter_controller_->view()->GetNativeWindow()); SetChildContent(flutter_controller_->view()->GetNativeWindow());
flutter_controller_->engine()->SetNextFrameCallback([&]() { flutter_controller_->engine()->SetNextFrameCallback([&]() {
this->Show(); this->Show();
}); });
return true; // Flutter can complete the first frame before the "show window" callback is
} // registered. The following call ensures a frame is pending to ensure the
// window is shown. It is a no-op if the first frame hasn't completed yet.
void FlutterWindow::OnDestroy() { flutter_controller_->ForceRedraw();
if (flutter_controller_) {
flutter_controller_ = nullptr; return true;
} }
Win32Window::OnDestroy(); void FlutterWindow::OnDestroy() {
} if (flutter_controller_) {
flutter_controller_ = nullptr;
LRESULT }
FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
WPARAM const wparam, Win32Window::OnDestroy();
LPARAM const lparam) noexcept { }
// Give Flutter, including plugins, an opportunity to handle window messages.
if (flutter_controller_) { LRESULT
std::optional<LRESULT> result = FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, WPARAM const wparam,
lparam); LPARAM const lparam) noexcept {
if (result) { // Give Flutter, including plugins, an opportunity to handle window messages.
return *result; if (flutter_controller_) {
} std::optional<LRESULT> result =
} flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
lparam);
switch (message) { if (result) {
case WM_FONTCHANGE: return *result;
flutter_controller_->engine()->ReloadSystemFonts(); }
break; }
}
switch (message) {
return Win32Window::MessageHandler(hwnd, message, wparam, lparam); case WM_FONTCHANGE:
} flutter_controller_->engine()->ReloadSystemFonts();
break;
}
return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
}

View File

@ -1,33 +1,33 @@
#ifndef RUNNER_FLUTTER_WINDOW_H_ #ifndef RUNNER_FLUTTER_WINDOW_H_
#define RUNNER_FLUTTER_WINDOW_H_ #define RUNNER_FLUTTER_WINDOW_H_
#include <flutter/dart_project.h> #include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h> #include <flutter/flutter_view_controller.h>
#include <memory> #include <memory>
#include "win32_window.h" #include "win32_window.h"
// A window that does nothing but host a Flutter view. // A window that does nothing but host a Flutter view.
class FlutterWindow : public Win32Window { class FlutterWindow : public Win32Window {
public: public:
// Creates a new FlutterWindow hosting a Flutter view running |project|. // Creates a new FlutterWindow hosting a Flutter view running |project|.
explicit FlutterWindow(const flutter::DartProject& project); explicit FlutterWindow(const flutter::DartProject& project);
virtual ~FlutterWindow(); virtual ~FlutterWindow();
protected: protected:
// Win32Window: // Win32Window:
bool OnCreate() override; bool OnCreate() override;
void OnDestroy() override; void OnDestroy() override;
LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
LPARAM const lparam) noexcept override; LPARAM const lparam) noexcept override;
private: private:
// The project to run. // The project to run.
flutter::DartProject project_; flutter::DartProject project_;
// The Flutter instance hosted by this window. // The Flutter instance hosted by this window.
std::unique_ptr<flutter::FlutterViewController> flutter_controller_; std::unique_ptr<flutter::FlutterViewController> flutter_controller_;
}; };
#endif // RUNNER_FLUTTER_WINDOW_H_ #endif // RUNNER_FLUTTER_WINDOW_H_

View File

@ -1,47 +1,47 @@
#include <flutter/dart_project.h> #include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h> #include <flutter/flutter_view_controller.h>
#include <windows.h> #include <windows.h>
#include "flutter_window.h" #include "flutter_window.h"
#include "utils.h" #include "utils.h"
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
_In_ wchar_t *command_line, _In_ int show_command) _In_ wchar_t *command_line, _In_ int show_command)
{ {
// Attach to console when present (e.g., 'flutter run') or create a // Attach to console when present (e.g., 'flutter run') or create a
// new console when running with a debugger. // new console when running with a debugger.
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent())
{ {
CreateAndAttachConsole(); CreateAndAttachConsole();
} }
// Initialize COM, so that it is available for use in the library and/or // Initialize COM, so that it is available for use in the library and/or
// plugins. // plugins.
::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
flutter::DartProject project(L"data"); flutter::DartProject project(L"data");
std::vector<std::string> command_line_arguments = std::vector<std::string> command_line_arguments =
GetCommandLineArguments(); GetCommandLineArguments();
project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
FlutterWindow window(project); FlutterWindow window(project);
Win32Window::Point origin(10, 10); Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720); Win32Window::Size size(1280, 720);
if (!window.Create(L"Freezer", origin, size)) if (!window.Create(L"Freezer", origin, size))
{ {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
window.SetQuitOnClose(true); window.SetQuitOnClose(true);
::MSG msg; ::MSG msg;
while (::GetMessage(&msg, nullptr, 0, 0)) while (::GetMessage(&msg, nullptr, 0, 0))
{ {
::TranslateMessage(&msg); ::TranslateMessage(&msg);
::DispatchMessage(&msg); ::DispatchMessage(&msg);
} }
::CoUninitialize(); ::CoUninitialize();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -1,16 +1,16 @@
//{{NO_DEPENDENCIES}} //{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file. // Microsoft Visual C++ generated include file.
// Used by Runner.rc // Used by Runner.rc
// //
#define IDI_APP_ICON 101 #define IDI_APP_ICON 101
// Next default values for new objects // Next default values for new objects
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif

View File

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3"> <application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings> <windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness> <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings> </windowsSettings>
</application> </application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application> <application>
<!-- Windows 10 and Windows 11 --> <!-- Windows 10 and Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 --> <!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 --> <!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 --> <!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
</application> </application>
</compatibility> </compatibility>
</assembly> </assembly>

Some files were not shown because too many files have changed in this diff Show More