mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Merge pull request #776 from wger-project/feature/build-process
Refactor the way the releases are built
This commit is contained in:
23
.github/actions/flutter-common/action.yml
vendored
Normal file
23
.github/actions/flutter-common/action.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: 'Flutter common setup'
|
||||
description: 'Common steps needed to setup the application'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
|
||||
- name: Setup Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: stable
|
||||
flutter-version: 3.29.2
|
||||
cache: true
|
||||
|
||||
- name: Install Flutter dependencies
|
||||
run: flutter pub get
|
||||
shell: bash
|
||||
|
||||
- name: Install Flutter dependencies
|
||||
run: |
|
||||
dart --version
|
||||
flutter --version
|
||||
shell: bash
|
||||
73
.github/workflows/build-android.yml
vendored
Normal file
73
.github/workflows/build-android.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
name: Build Android
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
ref:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
DECRYPTKEY_PLAYSTORE_SIGNING_KEY:
|
||||
required: true
|
||||
DECRYPTKEY_PROPERTIES:
|
||||
required: true
|
||||
jobs:
|
||||
build_android_apk:
|
||||
name: APK file
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout application
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
|
||||
- name: Common flutter setup
|
||||
uses: ./.github/actions/flutter-common
|
||||
|
||||
- name: Decrypt config files
|
||||
run: |
|
||||
cd ./fastlane/metadata/envfiles
|
||||
chmod +x ./decrypt_secrets.sh
|
||||
./decrypt_secrets.sh
|
||||
shell: bash
|
||||
env:
|
||||
DECRYPTKEY_PLAYSTORE_SIGNING_KEY: ${{ secrets.DECRYPTKEY_PLAYSTORE_SIGNING_KEY }}
|
||||
DECRYPTKEY_PROPERTIES: ${{ secrets.DECRYPTKEY_PROPERTIES }}
|
||||
|
||||
- name: Build APK
|
||||
run: flutter build apk --release
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: builds-apk
|
||||
path: build/app/outputs/flutter-apk/app-release.apk
|
||||
|
||||
build_android_aab:
|
||||
name: AAB file
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout application
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
|
||||
- name: Common setup
|
||||
uses: ./.github/actions/flutter-common
|
||||
|
||||
- name: Decrypt config files
|
||||
run: |
|
||||
cd ./fastlane/metadata/envfiles
|
||||
chmod +x ./decrypt_secrets.sh
|
||||
./decrypt_secrets.sh
|
||||
shell: bash
|
||||
env:
|
||||
DECRYPTKEY_PLAYSTORE: ${{ secrets.DECRYPTKEY_PLAYSTORE }}
|
||||
DECRYPTKEY_PLAYSTORE_SIGNING_KEY: ${{ secrets.DECRYPTKEY_PLAYSTORE_SIGNING_KEY }}
|
||||
DECRYPTKEY_PROPERTIES: ${{ secrets.DECRYPTKEY_PROPERTIES }}
|
||||
|
||||
- name: Build AAB
|
||||
run: flutter build appbundle --release
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: builds-aab
|
||||
path: build/app/outputs/bundle/release/app-release.aab
|
||||
47
.github/workflows/build-apple.yml
vendored
Normal file
47
.github/workflows/build-apple.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
name: Build Apple
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
ref:
|
||||
required: true
|
||||
type: string
|
||||
jobs:
|
||||
build_ios:
|
||||
name: iOS
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout application
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
|
||||
- name: Common flutter setup
|
||||
uses: ./.github/actions/flutter-common
|
||||
|
||||
- name: Build .app
|
||||
run: flutter build ios --release --no-codesign
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: builds-ios
|
||||
path: build/ios/iphoneos/Runner.app
|
||||
|
||||
build_macos:
|
||||
name: macOS
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout application
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
|
||||
- name: Common flutter setup
|
||||
uses: ./.github/actions/flutter-common
|
||||
|
||||
- name: Build .app
|
||||
run: flutter build macos --release
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: builds-macos
|
||||
path: build/macos/Build/Products/Release/wger.app
|
||||
37
.github/workflows/build-linux.yml
vendored
Normal file
37
.github/workflows/build-linux.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
#name: Build Linux
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
ref:
|
||||
required: true
|
||||
type: string
|
||||
jobs:
|
||||
build_linux:
|
||||
name: Flathub
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout application
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
|
||||
- name: Common setup
|
||||
uses: ./.github/actions/flutter-common
|
||||
|
||||
# Compare with list of available packages on the runner:
|
||||
# https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md
|
||||
- name: Build application for linux
|
||||
run: |
|
||||
# ninja-build
|
||||
sudo apt install -y pkg-config libgtk-3-dev liblzma-dev libstdc++-12-dev --no-install-recommends
|
||||
flutter build linux --release
|
||||
cd flatpak/scripts
|
||||
dart pub get
|
||||
dart flatpak_packager.dart --meta ../flatpak_meta.json --addTodaysVersion ${{inputs.ref}}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: builds-linux
|
||||
path: |
|
||||
flatpak/scripts/flatpak_generator_exports/wger-linux-x86_64.tar.gz
|
||||
flatpak/scripts/flatpak_generator_exports/wger-linux-x86_64.sha256
|
||||
127
.github/workflows/build-release.yml
vendored
127
.github/workflows/build-release.yml
vendored
@@ -1,127 +0,0 @@
|
||||
name: Build release artefacts
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
||||
|
||||
jobs:
|
||||
deploy_android:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout application code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'oracle'
|
||||
|
||||
- name: Setup Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: '3.2'
|
||||
|
||||
- name: Setup Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: stable
|
||||
flutter-version: 3.29.2
|
||||
|
||||
- name: Flutter info
|
||||
run: |
|
||||
dart --version
|
||||
flutter --version
|
||||
|
||||
- name: Install Flutter dependencies
|
||||
run: flutter pub get
|
||||
|
||||
- name: Decrypt config files
|
||||
run: |
|
||||
cd ./fastlane/metadata/envfiles
|
||||
chmod +x ./decrypt_secrets.sh
|
||||
./decrypt_secrets.sh
|
||||
env:
|
||||
DECRYPTKEY_PLAYSTORE: ${{ secrets.DECRYPTKEY_PLAYSTORE }}
|
||||
DECRYPTKEY_PLAYSTORE_SIGNING_KEY: ${{ secrets.DECRYPTKEY_PLAYSTORE_SIGNING_KEY }}
|
||||
DECRYPTKEY_PROPERTIES: ${{ secrets.DECRYPTKEY_PROPERTIES }}
|
||||
|
||||
- name: Extract version information
|
||||
run: |
|
||||
echo "VERSION_V=$(echo $GITHUB_REF | cut -d / -f 3)" >> $GITHUB_ENV
|
||||
echo "VERSION=$(echo $GITHUB_REF | cut -d / -f 3 | cut -c 2-)" >> $GITHUB_ENV
|
||||
echo "BUILD=$(flutter pub run cider version | cut -d '+' -f 2)" >> $GITHUB_ENV
|
||||
|
||||
- name: Bump pubspec version
|
||||
run: |
|
||||
flutter pub run cider version ${{ env.VERSION }}+${{ env.BUILD }}
|
||||
flutter pub run cider bump build
|
||||
|
||||
- name: Build application for linux
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev libstdc++-12-dev
|
||||
flutter build linux --release
|
||||
cd flatpak/scripts
|
||||
dart pub get
|
||||
dart flatpak_packager.dart --meta ../flatpak_meta.json --github --addTodaysVersion ${{ env.VERSION }}
|
||||
|
||||
- name: Build AAB
|
||||
run: flutter build appbundle --release
|
||||
|
||||
- name: Build APK
|
||||
run: flutter build apk --release
|
||||
|
||||
- name: Upload build to Play Store
|
||||
run: |
|
||||
bundle install
|
||||
bundle exec fastlane android production
|
||||
|
||||
- name: Make Github release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ env.VERSION }}
|
||||
files: |
|
||||
build/app/outputs/bundle/release/app-release.aab
|
||||
build/app/outputs/flutter-apk/app-release.apk
|
||||
flatpak/scripts/flatpak_generator_exports/wger-linux-x86_64.tar.gz
|
||||
flatpak/scripts/flatpak_generator_exports/wger-linux-x86_64.sha256
|
||||
|
||||
- name: Generate flathub manifest
|
||||
run: |
|
||||
cd flatpak/scripts
|
||||
dart pub get
|
||||
dart manifest_generator.dart --meta ../flatpak_meta.json --github
|
||||
mkdir ../../flathub
|
||||
cp flatpak_generator_exports/de.wger.flutter.json ../../flathub
|
||||
cp flatpak_generator_exports/flathub.json ../../flathub
|
||||
|
||||
- name: Push updated config to flathub repository
|
||||
uses: cpina/github-action-push-to-another-repository@main
|
||||
env:
|
||||
SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
|
||||
with:
|
||||
source-directory: flathub
|
||||
destination-github-username: wger-project
|
||||
destination-repository-name: de.wger.flutter
|
||||
user-email: github-actions@github.com
|
||||
target-branch: release-${{ env.VERSION }}
|
||||
create-target-branch-if-needed: true
|
||||
commit-message: Update to ${{ env.VERSION }}
|
||||
|
||||
# Note: the original tag that triggered the workflow is in the form vX.Y.Z
|
||||
# but the pubspec.yaml is committed in the commit after that one.
|
||||
# Since we need the tag to point to the correct commit for other workflows
|
||||
# such as f-droid we need a way to correct it. Only moving the tag
|
||||
# would not work, as it would trigger this workflow again. So as
|
||||
# a workaround, we use the v-tag to trigger this workflow, add a new
|
||||
# one without the v and push it.
|
||||
- name: Commit pubspec version and delete tag
|
||||
run: |
|
||||
git config user.name Github-Actions
|
||||
git config user.email github-actions@github.com
|
||||
git checkout -b release-${{ env.VERSION }}
|
||||
git add pubspec.yaml
|
||||
git commit -m "Bump version to $( flutter pub run cider version )"
|
||||
git push origin --delete ${{ env.VERSION_V }}
|
||||
git push --set-upstream origin release-${{ env.VERSION }}
|
||||
26
.github/workflows/build-windows.yml
vendored
Normal file
26
.github/workflows/build-windows.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
ref:
|
||||
required: true
|
||||
type: string
|
||||
jobs:
|
||||
build_windows:
|
||||
name: Windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout application
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
|
||||
- name: Common flutter setup
|
||||
uses: ./.github/actions/flutter-common
|
||||
|
||||
- name: Build .exe
|
||||
run: flutter build windows --release
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: builds-windows
|
||||
path: build\windows\x64\runner\Release\wger.exe
|
||||
47
.github/workflows/bump-version.yml
vendored
Normal file
47
.github/workflows/bump-version.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
app_version:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
determine_version:
|
||||
name: Create tag
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout application
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # needed to push changes
|
||||
|
||||
- name: Common flutter setup
|
||||
uses: ./.github/actions/flutter-common
|
||||
|
||||
- name: Validate version
|
||||
run: |
|
||||
RELEASE_VERSION="${{ inputs.app_version }}"
|
||||
if [[ ! "${{ inputs.app_version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Error: Input version '${{ inputs.app_version }}' is not in X.Y.Z format."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# In order to make sure the build number is the same across all platforms,
|
||||
# increase to the next multiple of 10. This is needed because the iOS process
|
||||
# is a bit more brittle and might need to be repeated if the App needs
|
||||
# to be re-submitted.
|
||||
- name: Bump pubspec version
|
||||
run: |
|
||||
CURRENT_BUILD=$(flutter pub run cider version | cut -d '+' -f 2)
|
||||
NEXT_BUILD=$(( (CURRENT_BUILD / 10 + 1) * 10 ))
|
||||
flutter pub run cider version ${{ inputs.app_version }}+${NEXT_BUILD}
|
||||
|
||||
- name: Commit pubspec
|
||||
run: |
|
||||
git config user.name Github-Actions
|
||||
git config user.email github-actions@github.com
|
||||
git add pubspec.yaml
|
||||
git tag ${{ inputs.app_version }}
|
||||
git commit -m "Bump version to $( flutter pub run cider version )"
|
||||
git push origin HEAD:master
|
||||
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@@ -9,21 +9,17 @@ on:
|
||||
paths:
|
||||
- '**.dart'
|
||||
- 'pubspec.yaml'
|
||||
workflow_call: { }
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Run tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
cache: true
|
||||
channel: 'stable'
|
||||
flutter-version: '3.29.x'
|
||||
|
||||
- run: dart --version
|
||||
- run: flutter --version
|
||||
- name: Common flutter setup
|
||||
uses: ./.github/actions/flutter-common
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
186
.github/workflows/make-release.yml
vendored
Normal file
186
.github/workflows/make-release.yml
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
name: Build release artefacts
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: Version to tag and release (X.Y.Z)
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
|
||||
ci:
|
||||
name: CI
|
||||
uses: ./.github/workflows/ci.yml
|
||||
|
||||
determine_version:
|
||||
needs: ci
|
||||
name: Prepare
|
||||
uses: ./.github/workflows/bump-version.yml
|
||||
with:
|
||||
app_version: ${{ github.event.inputs.version }}
|
||||
|
||||
build_linux:
|
||||
name: Linux
|
||||
needs: determine_version
|
||||
uses: ./.github/workflows/build-linux.yml
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version }}
|
||||
|
||||
|
||||
build_android:
|
||||
name: Android
|
||||
needs: determine_version
|
||||
uses: ./.github/workflows/build-android.yml
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version }}
|
||||
secrets:
|
||||
DECRYPTKEY_PLAYSTORE_SIGNING_KEY: ${{ secrets.DECRYPTKEY_PLAYSTORE_SIGNING_KEY }}
|
||||
DECRYPTKEY_PROPERTIES: ${{ secrets.DECRYPTKEY_PROPERTIES }}
|
||||
|
||||
build_apple:
|
||||
name: Apple
|
||||
needs: determine_version
|
||||
uses: ./.github/workflows/build-apple.yml
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version }}
|
||||
|
||||
build_windows:
|
||||
name: Microsoft
|
||||
needs: determine_version
|
||||
uses: ./.github/workflows/build-windows.yml
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version }}
|
||||
|
||||
upload_play_store:
|
||||
name: Upload to Play Store
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build_android
|
||||
- build_linux
|
||||
steps:
|
||||
- name: Checkout application
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version }}
|
||||
|
||||
- name: Download builds
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/
|
||||
|
||||
- name: Setup Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.4
|
||||
|
||||
- name: Decrypt config files
|
||||
run: |
|
||||
cd ./fastlane/metadata/envfiles
|
||||
chmod +x ./decrypt_secrets.sh
|
||||
./decrypt_secrets.sh
|
||||
shell: bash
|
||||
env:
|
||||
DECRYPTKEY_PLAYSTORE: ${{ secrets.DECRYPTKEY_PLAYSTORE }}
|
||||
|
||||
- name: Upload build to Play Store
|
||||
run: |
|
||||
mkdir -p ./build/app/outputs/bundle/release/
|
||||
cp /tmp/builds-aab/app-release.aab ./build/app/outputs/bundle/release/app-release.aab
|
||||
bundle install
|
||||
bundle exec fastlane android production
|
||||
|
||||
#
|
||||
# This is currently commented out since the iOS upload are currently being handled
|
||||
# by the fastlane script in the ios folder. We use the account of pthaler for this
|
||||
# and he runs the script manually.
|
||||
#
|
||||
|
||||
# upload_app_store:
|
||||
# name: Upload to App Store (placeholder)
|
||||
# runs-on: ubuntu-latest
|
||||
# needs:
|
||||
# - build_android
|
||||
# - build_apple
|
||||
# steps:
|
||||
# - name: Checkout application
|
||||
# uses: actions/checkout@v4
|
||||
# with:
|
||||
# ref: feature/build-process
|
||||
# # ref: ${{ github.event.inputs.version }}
|
||||
#
|
||||
# - name: Common flutter setup
|
||||
# uses: ./.github/actions/flutter-common
|
||||
#
|
||||
# - name: Download builds
|
||||
# uses: actions/download-artifact@v4
|
||||
# with:
|
||||
# path: /tmp/
|
||||
#
|
||||
# - name: Upload build to App Store
|
||||
# run: |
|
||||
# # bundle exec fastlane todo
|
||||
|
||||
make_gh_release:
|
||||
if: false
|
||||
name: Make Github Release
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- upload_play_store
|
||||
- build_linux
|
||||
- build_windows
|
||||
- build_apple
|
||||
|
||||
steps:
|
||||
- name: Download builds
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Make Github release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ inputs.version }}
|
||||
files: |
|
||||
builds-aab/app-release.aab
|
||||
builds-apk/app-release.apk
|
||||
builds-linux/wger-linux-x86_64.tar.gz
|
||||
builds-linux/wger-linux-x86_64.sha256
|
||||
builds-ios/Runner.app
|
||||
builds-macos/wger.app
|
||||
|
||||
generate_fathub_manifest:
|
||||
if: false
|
||||
runs-on: ubuntu-latest
|
||||
name: Upload flathub manifest
|
||||
needs:
|
||||
- make_gh_release
|
||||
steps:
|
||||
- name: Checkout application
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version }}
|
||||
|
||||
- name: Common flutter setup
|
||||
uses: ./.github/actions/flutter-common
|
||||
|
||||
- name: Generate manifest
|
||||
run: |
|
||||
cd flatpak/scripts
|
||||
dart pub get
|
||||
dart manifest_generator.dart --meta ../flatpak_meta.json --github
|
||||
mkdir ../../flathub
|
||||
cp flatpak_generator_exports/de.wger.flutter.json ../../flathub
|
||||
cp flatpak_generator_exports/flathub.json ../../flathub
|
||||
|
||||
- name: Push updated config to flathub repository
|
||||
uses: cpina/github-action-push-to-another-repository@main
|
||||
env:
|
||||
SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
|
||||
with:
|
||||
source-directory: flathub
|
||||
destination-github-username: wger-project
|
||||
destination-repository-name: de.wger.flutter
|
||||
user-email: github-actions@github.com
|
||||
target-branch: release-${{ github.event.inputs.version }}
|
||||
create-target-branch-if-needed: true
|
||||
commit-message: Update to ${{ github.event.inputs.version }}
|
||||
|
||||
@@ -6,14 +6,20 @@
|
||||
# To encrypt a new version of the keys:
|
||||
# gpg -c filename.json
|
||||
|
||||
echo "decrypting playstore API keys"
|
||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPTKEY_PLAYSTORE" \
|
||||
--output ./playstore.json playstore.json.gpg
|
||||
if [ -n "$DECRYPTKEY_PLAYSTORE" ]; then
|
||||
echo "decrypting playstore API keys"
|
||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPTKEY_PLAYSTORE" \
|
||||
--output ./playstore.json playstore.json.gpg
|
||||
fi
|
||||
|
||||
echo "decrypting key.properties"
|
||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPTKEY_PROPERTIES" \
|
||||
--output ./key.properties key.properties.gpg
|
||||
if [ -n "$DECRYPTKEY_PROPERTIES" ]; then
|
||||
echo "decrypting key.properties"
|
||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPTKEY_PROPERTIES" \
|
||||
--output ./key.properties key.properties.gpg
|
||||
fi
|
||||
|
||||
echo "decrypting playstore signing keys"
|
||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPTKEY_PLAYSTORE_SIGNING_KEY" \
|
||||
--output ./keys.jks keys.jks.gpg
|
||||
if [ -n "$DECRYPTKEY_PLAYSTORE_SIGNING_KEY" ]; then
|
||||
echo "decrypting playstore signing keys"
|
||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPTKEY_PLAYSTORE_SIGNING_KEY" \
|
||||
--output ./keys.jks keys.jks.gpg
|
||||
fi
|
||||
@@ -1,6 +1,7 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'flatpak_shared.dart';
|
||||
|
||||
/// Creates an archive containing all the sources for the Flatpak package for a
|
||||
@@ -25,7 +26,8 @@ void main(List<String> arguments) async {
|
||||
final metaIndex = arguments.indexOf('--meta');
|
||||
if (metaIndex == -1) {
|
||||
throw Exception(
|
||||
'You must run this script with a metadata file argument, using the --meta flag.');
|
||||
'You must run this script with a metadata file argument, using the --meta flag.',
|
||||
);
|
||||
}
|
||||
if (arguments.length == metaIndex + 1) {
|
||||
throw Exception('The --meta flag must be followed by the path to the metadata file.');
|
||||
@@ -54,12 +56,16 @@ void main(List<String> arguments) async {
|
||||
await outputDir.create();
|
||||
|
||||
final packageGenerator = PackageGenerator(
|
||||
inputDir: metaFile.parent, meta: meta, addedTodaysVersion: addedTodaysVersion);
|
||||
inputDir: metaFile.parent,
|
||||
meta: meta,
|
||||
addedTodaysVersion: addedTodaysVersion,
|
||||
);
|
||||
|
||||
await packageGenerator.generatePackage(
|
||||
outputDir,
|
||||
await PackageGenerator.runningOnARM() ? CPUArchitecture.aarch64 : CPUArchitecture.x86_64,
|
||||
fetchFromGithub);
|
||||
outputDir,
|
||||
await PackageGenerator.runningOnARM() ? CPUArchitecture.aarch64 : CPUArchitecture.x86_64,
|
||||
fetchFromGithub,
|
||||
);
|
||||
}
|
||||
|
||||
class PackageGenerator {
|
||||
@@ -67,10 +73,17 @@ class PackageGenerator {
|
||||
final FlatpakMeta meta;
|
||||
final String? addedTodaysVersion;
|
||||
|
||||
PackageGenerator({required this.inputDir, required this.meta, required this.addedTodaysVersion});
|
||||
const PackageGenerator({
|
||||
required this.inputDir,
|
||||
required this.meta,
|
||||
required this.addedTodaysVersion,
|
||||
});
|
||||
|
||||
Future<void> generatePackage(
|
||||
Directory outputDir, CPUArchitecture arch, bool fetchReleasesFromGithub) async {
|
||||
Directory outputDir,
|
||||
CPUArchitecture arch,
|
||||
bool fetchReleasesFromGithub,
|
||||
) async {
|
||||
final tempDir = await outputDir.createTemp('flutter_generator_temp');
|
||||
final appId = meta.appId;
|
||||
|
||||
@@ -79,7 +92,8 @@ class PackageGenerator {
|
||||
|
||||
if (!(await desktopFile.exists())) {
|
||||
throw Exception(
|
||||
'The desktop file does not exist under the specified path: ${desktopFile.path}');
|
||||
'The desktop file does not exist under the specified path: ${desktopFile.path}',
|
||||
);
|
||||
}
|
||||
|
||||
await desktopFile.copy('${tempDir.path}/$appId.desktop');
|
||||
@@ -101,12 +115,14 @@ class PackageGenerator {
|
||||
final origAppStreamFile = File('${inputDir.path}/${meta.appStreamPath}');
|
||||
if (!(await origAppStreamFile.exists())) {
|
||||
throw Exception(
|
||||
'The app data file does not exist under the specified path: ${origAppStreamFile.path}');
|
||||
'The app data file does not exist under the specified path: ${origAppStreamFile.path}',
|
||||
);
|
||||
}
|
||||
|
||||
final editedAppStreamContent = AppStreamModifier.replaceVersions(
|
||||
await origAppStreamFile.readAsString(),
|
||||
await meta.getReleases(fetchReleasesFromGithub, addedTodaysVersion));
|
||||
await origAppStreamFile.readAsString(),
|
||||
await meta.getReleases(fetchReleasesFromGithub, addedTodaysVersion),
|
||||
);
|
||||
|
||||
final editedAppStreamFile = File('${tempDir.path}/$appId.metainfo.xml');
|
||||
await editedAppStreamFile.writeAsString(editedAppStreamContent);
|
||||
@@ -117,7 +133,8 @@ class PackageGenerator {
|
||||
final buildDir = Directory(bundlePath);
|
||||
if (!(await buildDir.exists())) {
|
||||
throw Exception(
|
||||
'The linux build directory does not exist under the specified path: ${buildDir.path}');
|
||||
'The linux build directory does not exist under the specified path: ${buildDir.path}',
|
||||
);
|
||||
}
|
||||
final destDir = Directory('${tempDir.path}/bin');
|
||||
await destDir.create();
|
||||
@@ -159,9 +176,10 @@ class AppStreamModifier {
|
||||
.replaceAll('\n', '<~>')
|
||||
.replaceFirst(RegExp('<releases.*</releases>'), releasesSection)
|
||||
.replaceAll('<~>', '\n');
|
||||
} else {
|
||||
return origAppStreamContent.replaceFirst(
|
||||
'</component>', '\n\t$releasesSection\n</component>');
|
||||
}
|
||||
return origAppStreamContent.replaceFirst(
|
||||
'</component>',
|
||||
'\n\t$releasesSection\n</component>',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ class Release {
|
||||
final String version;
|
||||
final String date; //TODO add resources
|
||||
|
||||
Release({required this.version, required this.date});
|
||||
const Release({required this.version, required this.date});
|
||||
}
|
||||
|
||||
enum CPUArchitecture {
|
||||
@@ -18,6 +18,7 @@ enum CPUArchitecture {
|
||||
|
||||
final String flatpakArchCode;
|
||||
final String flutterDirName;
|
||||
|
||||
const CPUArchitecture(this.flatpakArchCode, this.flutterDirName);
|
||||
}
|
||||
|
||||
@@ -27,11 +28,12 @@ class ReleaseAsset {
|
||||
final bool isRelativeLocalPath;
|
||||
final String tarballSha256;
|
||||
|
||||
ReleaseAsset(
|
||||
{required this.arch,
|
||||
required this.tarballUrlOrPath,
|
||||
required this.isRelativeLocalPath,
|
||||
required this.tarballSha256});
|
||||
const ReleaseAsset({
|
||||
required this.arch,
|
||||
required this.tarballUrlOrPath,
|
||||
required this.isRelativeLocalPath,
|
||||
required this.tarballSha256,
|
||||
});
|
||||
}
|
||||
|
||||
class Icon {
|
||||
@@ -72,9 +74,10 @@ class GithubReleases {
|
||||
|
||||
Future<void> _fetchReleasesAndAssets(bool canBeEmpty) async {
|
||||
final releaseJsonContent = (await http.get(Uri(
|
||||
scheme: 'https',
|
||||
host: 'api.github.com',
|
||||
path: '/repos/$githubReleaseOrganization/$githubReleaseProject/releases')))
|
||||
scheme: 'https',
|
||||
host: 'api.github.com',
|
||||
path: '/repos/$githubReleaseOrganization/$githubReleaseProject/releases',
|
||||
)))
|
||||
.body;
|
||||
final decodedJson = jsonDecode(releaseJsonContent) as List;
|
||||
|
||||
@@ -154,17 +157,19 @@ class GithubReleases {
|
||||
final res = List<ReleaseAsset>.empty(growable: true);
|
||||
if (x64TarballUrl != null && x64Sha != null) {
|
||||
res.add(ReleaseAsset(
|
||||
arch: CPUArchitecture.x86_64,
|
||||
tarballUrlOrPath: x64TarballUrl,
|
||||
isRelativeLocalPath: false,
|
||||
tarballSha256: x64Sha));
|
||||
arch: CPUArchitecture.x86_64,
|
||||
tarballUrlOrPath: x64TarballUrl,
|
||||
isRelativeLocalPath: false,
|
||||
tarballSha256: x64Sha,
|
||||
));
|
||||
}
|
||||
if (aarch64TarballUrl != null && aarch64Sha != null) {
|
||||
res.add(ReleaseAsset(
|
||||
arch: CPUArchitecture.aarch64,
|
||||
tarballUrlOrPath: aarch64TarballUrl,
|
||||
isRelativeLocalPath: false,
|
||||
tarballSha256: aarch64Sha));
|
||||
arch: CPUArchitecture.aarch64,
|
||||
tarballUrlOrPath: aarch64TarballUrl,
|
||||
isRelativeLocalPath: false,
|
||||
tarballSha256: aarch64Sha,
|
||||
));
|
||||
}
|
||||
return res.isEmpty ? null : res;
|
||||
}
|
||||
@@ -196,22 +201,22 @@ class FlatpakMeta {
|
||||
final String? githubReleaseProject;
|
||||
late final GithubReleases? _githubReleases;
|
||||
|
||||
FlatpakMeta(
|
||||
{required this.appId,
|
||||
required this.lowercaseAppName,
|
||||
required this.githubReleaseOrganization,
|
||||
required this.githubReleaseProject,
|
||||
required List<Release>? localReleases,
|
||||
required List<ReleaseAsset>? localReleaseAssets,
|
||||
required this.localLinuxBuildDir,
|
||||
required this.appStreamPath,
|
||||
required this.desktopPath,
|
||||
required this.icons,
|
||||
required this.freedesktopRuntime,
|
||||
required this.buildCommandsAfterUnpack,
|
||||
required this.extraModules,
|
||||
required this.finishArgs})
|
||||
: _localReleases = localReleases,
|
||||
FlatpakMeta({
|
||||
required this.appId,
|
||||
required this.lowercaseAppName,
|
||||
required this.githubReleaseOrganization,
|
||||
required this.githubReleaseProject,
|
||||
required List<Release>? localReleases,
|
||||
required List<ReleaseAsset>? localReleaseAssets,
|
||||
required this.localLinuxBuildDir,
|
||||
required this.appStreamPath,
|
||||
required this.desktopPath,
|
||||
required this.icons,
|
||||
required this.freedesktopRuntime,
|
||||
required this.buildCommandsAfterUnpack,
|
||||
required this.extraModules,
|
||||
required this.finishArgs,
|
||||
}) : _localReleases = localReleases,
|
||||
_localReleaseAssets = localReleaseAssets {
|
||||
if (githubReleaseOrganization != null && githubReleaseProject != null) {
|
||||
_githubReleases = GithubReleases(githubReleaseOrganization!, githubReleaseProject!);
|
||||
@@ -219,16 +224,21 @@ class FlatpakMeta {
|
||||
}
|
||||
|
||||
Future<List<Release>> getReleases(
|
||||
bool fetchReleasesFromGithub, String? addedTodaysVersion) async {
|
||||
bool fetchReleasesFromGithub,
|
||||
String? addedTodaysVersion,
|
||||
) async {
|
||||
final releases = List<Release>.empty(growable: true);
|
||||
if (addedTodaysVersion != null) {
|
||||
releases.add(Release(
|
||||
version: addedTodaysVersion, date: DateTime.now().toIso8601String().split('T').first));
|
||||
version: addedTodaysVersion,
|
||||
date: DateTime.now().toIso8601String().split('T').first,
|
||||
));
|
||||
}
|
||||
if (fetchReleasesFromGithub) {
|
||||
if (_githubReleases == null) {
|
||||
throw Exception(
|
||||
'Metadata must include Github repository info if fetching releases from Github.');
|
||||
'Metadata must include Github repository info if fetching releases from Github.',
|
||||
);
|
||||
}
|
||||
releases.addAll(await _githubReleases!.getReleases(addedTodaysVersion != null));
|
||||
} else {
|
||||
@@ -246,71 +256,73 @@ class FlatpakMeta {
|
||||
if (fetchReleasesFromGithub) {
|
||||
if (_githubReleases == null) {
|
||||
throw Exception(
|
||||
'Metadata must include Github repository info if fetching releases from Github.');
|
||||
'Metadata must include Github repository info if fetching releases from Github.',
|
||||
);
|
||||
}
|
||||
return _githubReleases!.getLatestReleaseAssets();
|
||||
} else {
|
||||
if (_localReleases == null) {
|
||||
throw Exception('Metadata must include releases if not fetching releases from Github.');
|
||||
}
|
||||
return _localReleaseAssets;
|
||||
}
|
||||
if (_localReleases == null) {
|
||||
throw Exception('Metadata must include releases if not fetching releases from Github.');
|
||||
}
|
||||
return _localReleaseAssets;
|
||||
}
|
||||
|
||||
static FlatpakMeta fromJson(File jsonFile, {bool skipLocalReleases = false}) {
|
||||
try {
|
||||
final dynamic json = jsonDecode(jsonFile.readAsStringSync());
|
||||
return FlatpakMeta(
|
||||
appId: json['appId'] as String,
|
||||
lowercaseAppName: json['lowercaseAppName'] as String,
|
||||
githubReleaseOrganization: json['githubReleaseOrganization'] as String?,
|
||||
githubReleaseProject: json['githubReleaseProject'] as String?,
|
||||
localReleases: skipLocalReleases
|
||||
? null
|
||||
: (json['localReleases'] as List?)?.map((dynamic r) {
|
||||
final rMap = r as Map;
|
||||
return Release(version: rMap['version'] as String, date: rMap['date'] as String);
|
||||
}).toList(),
|
||||
localReleaseAssets: skipLocalReleases
|
||||
? null
|
||||
: (json['localReleaseAssets'] as List?)?.map((dynamic ra) {
|
||||
final raMap = ra as Map;
|
||||
final archString = raMap['arch'] as String;
|
||||
final arch = (archString == CPUArchitecture.x86_64.flatpakArchCode)
|
||||
? CPUArchitecture.x86_64
|
||||
: (archString == CPUArchitecture.aarch64.flatpakArchCode)
|
||||
? CPUArchitecture.aarch64
|
||||
: null;
|
||||
if (arch == null) {
|
||||
throw Exception(
|
||||
'Architecture must be either "${CPUArchitecture.x86_64.flatpakArchCode}" or "${CPUArchitecture.aarch64.flatpakArchCode}"');
|
||||
}
|
||||
final tarballFile =
|
||||
File('${jsonFile.parent.path}/${raMap['tarballPath'] as String}');
|
||||
final tarballPath = tarballFile.absolute.path;
|
||||
final preShasum = Process.runSync('shasum', ['-a', '256', tarballPath]);
|
||||
final shasum = preShasum.stdout.toString().split(' ').first;
|
||||
if (preShasum.exitCode != 0) {
|
||||
throw Exception(preShasum.stderr);
|
||||
}
|
||||
return ReleaseAsset(
|
||||
arch: arch,
|
||||
tarballUrlOrPath: tarballPath,
|
||||
isRelativeLocalPath: true,
|
||||
tarballSha256: shasum);
|
||||
}).toList(),
|
||||
localLinuxBuildDir: json['localLinuxBuildDir'] as String,
|
||||
appStreamPath: json['appStreamPath'] as String,
|
||||
desktopPath: json['desktopPath'] as String,
|
||||
icons: (json['icons'] as Map).entries.map((mapEntry) {
|
||||
return Icon(type: mapEntry.key as String, path: mapEntry.value as String);
|
||||
}).toList(),
|
||||
freedesktopRuntime: json['freedesktopRuntime'] as String,
|
||||
buildCommandsAfterUnpack: (json['buildCommandsAfterUnpack'] as List?)
|
||||
?.map((dynamic bc) => bc as String)
|
||||
.toList(),
|
||||
extraModules: json['extraModules'] as List?,
|
||||
finishArgs: (json['finishArgs'] as List).map((dynamic fa) => fa as String).toList());
|
||||
appId: json['appId'] as String,
|
||||
lowercaseAppName: json['lowercaseAppName'] as String,
|
||||
githubReleaseOrganization: json['githubReleaseOrganization'] as String?,
|
||||
githubReleaseProject: json['githubReleaseProject'] as String?,
|
||||
localReleases: skipLocalReleases
|
||||
? null
|
||||
: (json['localReleases'] as List?)?.map((dynamic r) {
|
||||
final rMap = r as Map;
|
||||
return Release(version: rMap['version'] as String, date: rMap['date'] as String);
|
||||
}).toList(),
|
||||
localReleaseAssets: skipLocalReleases
|
||||
? null
|
||||
: (json['localReleaseAssets'] as List?)?.map((dynamic ra) {
|
||||
final raMap = ra as Map;
|
||||
final archString = raMap['arch'] as String;
|
||||
final arch = (archString == CPUArchitecture.x86_64.flatpakArchCode)
|
||||
? CPUArchitecture.x86_64
|
||||
: (archString == CPUArchitecture.aarch64.flatpakArchCode)
|
||||
? CPUArchitecture.aarch64
|
||||
: null;
|
||||
if (arch == null) {
|
||||
throw Exception(
|
||||
'Architecture must be either "${CPUArchitecture.x86_64.flatpakArchCode}" or "${CPUArchitecture.aarch64.flatpakArchCode}"',
|
||||
);
|
||||
}
|
||||
final tarballFile =
|
||||
File('${jsonFile.parent.path}/${raMap['tarballPath'] as String}');
|
||||
final tarballPath = tarballFile.absolute.path;
|
||||
final preShasum = Process.runSync('shasum', ['-a', '256', tarballPath]);
|
||||
final shasum = preShasum.stdout.toString().split(' ').first;
|
||||
if (preShasum.exitCode != 0) {
|
||||
throw Exception(preShasum.stderr);
|
||||
}
|
||||
return ReleaseAsset(
|
||||
arch: arch,
|
||||
tarballUrlOrPath: tarballPath,
|
||||
isRelativeLocalPath: true,
|
||||
tarballSha256: shasum,
|
||||
);
|
||||
}).toList(),
|
||||
localLinuxBuildDir: json['localLinuxBuildDir'] as String,
|
||||
appStreamPath: json['appStreamPath'] as String,
|
||||
desktopPath: json['desktopPath'] as String,
|
||||
icons: (json['icons'] as Map).entries.map((mapEntry) {
|
||||
return Icon(type: mapEntry.key as String, path: mapEntry.value as String);
|
||||
}).toList(),
|
||||
freedesktopRuntime: json['freedesktopRuntime'] as String,
|
||||
buildCommandsAfterUnpack:
|
||||
(json['buildCommandsAfterUnpack'] as List?)?.map((dynamic bc) => bc as String).toList(),
|
||||
extraModules: json['extraModules'] as List?,
|
||||
finishArgs: (json['finishArgs'] as List).map((dynamic fa) => fa as String).toList(),
|
||||
);
|
||||
} catch (e) {
|
||||
throw Exception('Could not parse JSON file, due to this error:\n$e');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
platform :ios, '12.0'
|
||||
platform :ios, '14.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
@@ -5,6 +5,7 @@ project(runner LANGUAGES CXX)
|
||||
# The name of the executable created for the application. Change this to change
|
||||
# the on-disk name of your application.
|
||||
set(BINARY_NAME "wger")
|
||||
|
||||
# The unique GTK application identifier for this application. See:
|
||||
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
||||
set(APPLICATION_ID "de.wger.flutter")
|
||||
@@ -17,22 +18,22 @@ cmake_policy(SET CMP0063 NEW)
|
||||
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
|
||||
|
||||
# Root filesystem for cross-building.
|
||||
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
|
||||
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
|
||||
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
endif()
|
||||
if (FLUTTER_TARGET_PLATFORM_SYSROOT)
|
||||
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
|
||||
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
endif ()
|
||||
|
||||
# Define build configuration options.
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE "Debug" CACHE
|
||||
STRING "Flutter build mode" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
||||
"Debug" "Profile" "Release")
|
||||
endif()
|
||||
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE "Debug" CACHE
|
||||
STRING "Flutter build mode" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
||||
"Debug" "Profile" "Release")
|
||||
endif ()
|
||||
|
||||
# Compilation settings that should be applied to most targets.
|
||||
#
|
||||
@@ -40,14 +41,15 @@ endif()
|
||||
# default. In most cases, you should add new options to specific targets instead
|
||||
# of modifying this function.
|
||||
function(APPLY_STANDARD_SETTINGS TARGET)
|
||||
target_compile_features(${TARGET} PUBLIC cxx_std_14)
|
||||
target_compile_features(${TARGET} PUBLIC cxx_std_14)
|
||||
|
||||
# Workaround for https://github.com/wger-project/flutter/issues/577 / https://github.com/rive-app/rive-flutter/issues/390
|
||||
#target_compile_options(${TARGET} PRIVATE -Wall -Werror) -- original options
|
||||
target_compile_options(${TARGET} PRIVATE -Wall -Werror -Wno-unused-variable -Wno-unused-function)
|
||||
# Roland:
|
||||
# Workaround for https://github.com/wger-project/flutter/issues/577 / https://github.com/rive-app/rive-flutter/issues/390
|
||||
#target_compile_options(${TARGET} PRIVATE -Wall -Werror) -- original options
|
||||
target_compile_options(${TARGET} PRIVATE -Wall -Werror -Wno-unused-variable -Wno-unused-function)
|
||||
|
||||
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
|
||||
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
|
||||
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
|
||||
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
|
||||
endfunction()
|
||||
|
||||
# Flutter library and tool build rules.
|
||||
@@ -65,9 +67,9 @@ add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
|
||||
#
|
||||
# Any new source files that you add to the application should be added here.
|
||||
add_executable(${BINARY_NAME}
|
||||
"main.cc"
|
||||
"my_application.cc"
|
||||
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
|
||||
"main.cc"
|
||||
"my_application.cc"
|
||||
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
|
||||
)
|
||||
|
||||
# Apply the standard set of build settings. This can be removed for applications
|
||||
@@ -86,8 +88,8 @@ add_dependencies(${BINARY_NAME} flutter_assemble)
|
||||
# people trying to run the unbundled copy, put it in a subdirectory instead of
|
||||
# the default top-level location.
|
||||
set_target_properties(${BINARY_NAME}
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
|
||||
)
|
||||
|
||||
# Generated plugin build rules, which manage building the plugins and adding
|
||||
@@ -99,9 +101,9 @@ include(flutter/generated_plugins.cmake)
|
||||
# By default, "installing" just makes a relocatable bundle in the build
|
||||
# directory.
|
||||
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
|
||||
endif()
|
||||
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
|
||||
endif ()
|
||||
|
||||
# Start with a clean build bundle directory every time.
|
||||
install(CODE "
|
||||
@@ -112,19 +114,19 @@ set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
|
||||
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
|
||||
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
|
||||
COMPONENT Runtime)
|
||||
COMPONENT Runtime)
|
||||
|
||||
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
|
||||
COMPONENT Runtime)
|
||||
COMPONENT Runtime)
|
||||
|
||||
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
COMPONENT Runtime)
|
||||
|
||||
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
|
||||
install(FILES "${bundled_library}"
|
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
endforeach(bundled_library)
|
||||
foreach (bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
|
||||
install(FILES "${bundled_library}"
|
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
endforeach (bundled_library)
|
||||
|
||||
# Fully re-copy the assets directory on each build to avoid having stale files
|
||||
# from a previous install.
|
||||
@@ -133,10 +135,10 @@ install(CODE "
|
||||
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
|
||||
" COMPONENT Runtime)
|
||||
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.
|
||||
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
endif()
|
||||
if (NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
endif ()
|
||||
|
||||
@@ -14,20 +14,21 @@ PODS:
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- sqlite3 (3.47.0):
|
||||
- sqlite3/common (= 3.47.0)
|
||||
- sqlite3/common (3.47.0)
|
||||
- sqlite3/dbstatvtab (3.47.0):
|
||||
- sqlite3 (3.49.1):
|
||||
- sqlite3/common (= 3.49.1)
|
||||
- sqlite3/common (3.49.1)
|
||||
- sqlite3/dbstatvtab (3.49.1):
|
||||
- sqlite3/common
|
||||
- sqlite3/fts5 (3.47.0):
|
||||
- sqlite3/fts5 (3.49.1):
|
||||
- sqlite3/common
|
||||
- sqlite3/perf-threadsafe (3.47.0):
|
||||
- sqlite3/perf-threadsafe (3.49.1):
|
||||
- sqlite3/common
|
||||
- sqlite3/rtree (3.47.0):
|
||||
- sqlite3/rtree (3.49.1):
|
||||
- sqlite3/common
|
||||
- sqlite3_flutter_libs (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- sqlite3 (~> 3.47.0)
|
||||
- sqlite3 (~> 3.49.1)
|
||||
- sqlite3/dbstatvtab
|
||||
- sqlite3/fts5
|
||||
- sqlite3/perf-threadsafe
|
||||
@@ -46,7 +47,7 @@ DEPENDENCIES:
|
||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- rive_common (from `Flutter/ephemeral/.symlinks/plugins/rive_common/macos`)
|
||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos`)
|
||||
- sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`)
|
||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||
- video_player_avfoundation (from `Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin`)
|
||||
|
||||
@@ -70,25 +71,25 @@ EXTERNAL SOURCES:
|
||||
shared_preferences_foundation:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
||||
sqlite3_flutter_libs:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin
|
||||
url_launcher_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
|
||||
video_player_avfoundation:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d
|
||||
flutter_zxing: ea030278aa2a051cd81a5b0053be9d0569d11c9a
|
||||
file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31
|
||||
flutter_zxing: 91e9d17c79c60860450e8879cced0ec54f6a2601
|
||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||
package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
rive_common: 0f0aadf670f0c6a7872dfe3e6186f112a5319108
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sqlite3: 0aa20658a9b238a3b1ff7175eb7bdd863b0ab4fd
|
||||
sqlite3_flutter_libs: f0b7a85544d8bac7b8bac12eac7d05bcfdd786d0
|
||||
url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404
|
||||
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
|
||||
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
|
||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||
rive_common: ea79040f86acf053a2d5a75a2506175ee39796a5
|
||||
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
||||
sqlite3: fc1400008a9b3525f5914ed715a5d1af0b8f4983
|
||||
sqlite3_flutter_libs: f8fc13346870e73fe35ebf6dbb997fbcd156b241
|
||||
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
|
||||
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
|
||||
|
||||
PODFILE CHECKSUM: 0d3963a09fc94f580682bd88480486da345dc3f0
|
||||
|
||||
COCOAPODS: 1.16.0
|
||||
COCOAPODS: 1.16.2
|
||||
|
||||
17
windows/.gitignore
vendored
Normal file
17
windows/.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
flutter/ephemeral/
|
||||
|
||||
# Visual Studio user-specific files.
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# Visual Studio build-related files.
|
||||
x64/
|
||||
x86/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
111
windows/CMakeLists.txt
Normal file
111
windows/CMakeLists.txt
Normal file
@@ -0,0 +1,111 @@
|
||||
# Project-level configuration.
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(wger LANGUAGES CXX)
|
||||
|
||||
# The name of the executable created for the application. Change this to change
|
||||
# the on-disk name of your application.
|
||||
set(BINARY_NAME "wger")
|
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||
# versions of CMake.
|
||||
cmake_policy(VERSION 3.14...3.25)
|
||||
|
||||
# Define build configuration option.
|
||||
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if (IS_MULTICONFIG)
|
||||
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
|
||||
CACHE STRING "" FORCE)
|
||||
else ()
|
||||
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE "Debug" CACHE
|
||||
STRING "Flutter build mode" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
||||
"Debug" "Profile" "Release")
|
||||
endif ()
|
||||
endif ()
|
||||
# Define settings for the Profile build mode.
|
||||
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_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_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
|
||||
# Use Unicode for all projects.
|
||||
add_definitions(-DUNICODE -D_UNICODE)
|
||||
|
||||
# Compilation settings that should be applied to most targets.
|
||||
#
|
||||
# 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
|
||||
# of modifying this function.
|
||||
function(APPLY_STANDARD_SETTINGS TARGET)
|
||||
target_compile_features(${TARGET} PUBLIC cxx_std_17)
|
||||
|
||||
# Workaround for https://github.com/wger-project/flutter/issues/577 / https://github.com/rive-app/rive-flutter/issues/390
|
||||
# target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") --> Original options
|
||||
target_compile_options(${TARGET} PRIVATE /W4 /wd"4100")
|
||||
target_compile_options(${TARGET} PRIVATE /EHsc)
|
||||
target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
|
||||
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
|
||||
endfunction()
|
||||
|
||||
# Flutter library and tool build rules.
|
||||
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
|
||||
add_subdirectory(${FLUTTER_MANAGED_DIR})
|
||||
|
||||
# Application build; see runner/CMakeLists.txt.
|
||||
add_subdirectory("runner")
|
||||
|
||||
|
||||
# Generated plugin build rules, which manage building the plugins and adding
|
||||
# them to the application.
|
||||
include(flutter/generated_plugins.cmake)
|
||||
|
||||
|
||||
# === Installation ===
|
||||
# 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)
|
||||
# so that building and running from within Visual Studio will work.
|
||||
set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
|
||||
# Make the "install" step default, as it's required to run.
|
||||
set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
|
||||
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
|
||||
endif ()
|
||||
|
||||
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
|
||||
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
|
||||
|
||||
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
if (PLUGIN_BUNDLED_LIBRARIES)
|
||||
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
|
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
endif ()
|
||||
|
||||
# Copy the native assets provided by the build.dart from all packages.
|
||||
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
|
||||
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
|
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
# Fully re-copy the assets directory on each build to avoid having stale files
|
||||
# from a previous install.
|
||||
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
|
||||
install(CODE "
|
||||
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
|
||||
" COMPONENT Runtime)
|
||||
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
|
||||
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
|
||||
|
||||
# Install the AOT library on non-Debug builds only.
|
||||
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
|
||||
CONFIGURATIONS Profile;Release
|
||||
COMPONENT Runtime)
|
||||
109
windows/flutter/CMakeLists.txt
Normal file
109
windows/flutter/CMakeLists.txt
Normal file
@@ -0,0 +1,109 @@
|
||||
# This file controls Flutter-level build steps. It should not be edited.
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
|
||||
|
||||
# Configuration provided via flutter tool.
|
||||
include(${EPHEMERAL_DIR}/generated_config.cmake)
|
||||
|
||||
# TODO: Move the rest of this into files in ephemeral. See
|
||||
# https://github.com/flutter/flutter/issues/57146.
|
||||
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
|
||||
|
||||
# Set fallback configurations for older versions of the flutter tool.
|
||||
if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
|
||||
set(FLUTTER_TARGET_PLATFORM "windows-x64")
|
||||
endif()
|
||||
|
||||
# === Flutter Library ===
|
||||
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
|
||||
|
||||
# Published to parent scope for install step.
|
||||
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
|
||||
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
|
||||
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
|
||||
set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
|
||||
|
||||
list(APPEND FLUTTER_LIBRARY_HEADERS
|
||||
"flutter_export.h"
|
||||
"flutter_windows.h"
|
||||
"flutter_messenger.h"
|
||||
"flutter_plugin_registrar.h"
|
||||
"flutter_texture_registrar.h"
|
||||
)
|
||||
list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
|
||||
add_library(flutter INTERFACE)
|
||||
target_include_directories(flutter INTERFACE
|
||||
"${EPHEMERAL_DIR}"
|
||||
)
|
||||
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
|
||||
add_dependencies(flutter flutter_assemble)
|
||||
|
||||
# === Wrapper ===
|
||||
list(APPEND CPP_WRAPPER_SOURCES_CORE
|
||||
"core_implementations.cc"
|
||||
"standard_codec.cc"
|
||||
)
|
||||
list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
|
||||
list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
|
||||
"plugin_registrar.cc"
|
||||
)
|
||||
list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
|
||||
list(APPEND CPP_WRAPPER_SOURCES_APP
|
||||
"flutter_engine.cc"
|
||||
"flutter_view_controller.cc"
|
||||
)
|
||||
list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
|
||||
|
||||
# Wrapper sources needed for a plugin.
|
||||
add_library(flutter_wrapper_plugin STATIC
|
||||
${CPP_WRAPPER_SOURCES_CORE}
|
||||
${CPP_WRAPPER_SOURCES_PLUGIN}
|
||||
)
|
||||
apply_standard_settings(flutter_wrapper_plugin)
|
||||
set_target_properties(flutter_wrapper_plugin PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE ON)
|
||||
set_target_properties(flutter_wrapper_plugin PROPERTIES
|
||||
CXX_VISIBILITY_PRESET hidden)
|
||||
target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
|
||||
target_include_directories(flutter_wrapper_plugin PUBLIC
|
||||
"${WRAPPER_ROOT}/include"
|
||||
)
|
||||
add_dependencies(flutter_wrapper_plugin flutter_assemble)
|
||||
|
||||
# Wrapper sources needed for the runner.
|
||||
add_library(flutter_wrapper_app STATIC
|
||||
${CPP_WRAPPER_SOURCES_CORE}
|
||||
${CPP_WRAPPER_SOURCES_APP}
|
||||
)
|
||||
apply_standard_settings(flutter_wrapper_app)
|
||||
target_link_libraries(flutter_wrapper_app PUBLIC flutter)
|
||||
target_include_directories(flutter_wrapper_app PUBLIC
|
||||
"${WRAPPER_ROOT}/include"
|
||||
)
|
||||
add_dependencies(flutter_wrapper_app flutter_assemble)
|
||||
|
||||
# === Flutter tool backend ===
|
||||
# _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
|
||||
# flutter tool.
|
||||
set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
|
||||
set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
|
||||
add_custom_command(
|
||||
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
|
||||
${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
|
||||
${CPP_WRAPPER_SOURCES_APP}
|
||||
${PHONY_OUTPUT}
|
||||
COMMAND ${CMAKE_COMMAND} -E env
|
||||
${FLUTTER_TOOL_ENVIRONMENT}
|
||||
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
|
||||
${FLUTTER_TARGET_PLATFORM} $<CONFIG>
|
||||
VERBATIM
|
||||
)
|
||||
add_custom_target(flutter_assemble DEPENDS
|
||||
"${FLUTTER_LIBRARY}"
|
||||
${FLUTTER_LIBRARY_HEADERS}
|
||||
${CPP_WRAPPER_SOURCES_CORE}
|
||||
${CPP_WRAPPER_SOURCES_PLUGIN}
|
||||
${CPP_WRAPPER_SOURCES_APP}
|
||||
)
|
||||
23
windows/flutter/generated_plugin_registrant.cc
Normal file
23
windows/flutter/generated_plugin_registrant.cc
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <rive_common/rive_plugin.h>
|
||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
RivePluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("RivePlugin"));
|
||||
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
}
|
||||
15
windows/flutter/generated_plugin_registrant.h
Normal file
15
windows/flutter/generated_plugin_registrant.h
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifndef GENERATED_PLUGIN_REGISTRANT_
|
||||
#define GENERATED_PLUGIN_REGISTRANT_
|
||||
|
||||
#include <flutter/plugin_registry.h>
|
||||
|
||||
// Registers Flutter plugins.
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry);
|
||||
|
||||
#endif // GENERATED_PLUGIN_REGISTRANT_
|
||||
28
windows/flutter/generated_plugins.cmake
Normal file
28
windows/flutter/generated_plugins.cmake
Normal file
@@ -0,0 +1,28 @@
|
||||
#
|
||||
# Generated file, do not edit.
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_windows
|
||||
rive_common
|
||||
sqlite3_flutter_libs
|
||||
url_launcher_windows
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
flutter_zxing
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
||||
foreach(plugin ${FLUTTER_PLUGIN_LIST})
|
||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
|
||||
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
|
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
|
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
|
||||
endforeach(plugin)
|
||||
|
||||
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
|
||||
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
|
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
|
||||
endforeach(ffi_plugin)
|
||||
40
windows/runner/CMakeLists.txt
Normal file
40
windows/runner/CMakeLists.txt
Normal file
@@ -0,0 +1,40 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(runner LANGUAGES CXX)
|
||||
|
||||
# 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
|
||||
# work.
|
||||
#
|
||||
# Any new source files that you add to the application should be added here.
|
||||
add_executable(${BINARY_NAME} WIN32
|
||||
"flutter_window.cpp"
|
||||
"main.cpp"
|
||||
"utils.cpp"
|
||||
"win32_window.cpp"
|
||||
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
|
||||
"Runner.rc"
|
||||
"runner.exe.manifest"
|
||||
)
|
||||
|
||||
# Apply the standard set of build settings. This can be removed for applications
|
||||
# that need different build settings.
|
||||
apply_standard_settings(${BINARY_NAME})
|
||||
|
||||
# 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_MAJOR=${FLUTTER_VERSION_MAJOR}")
|
||||
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_BUILD=${FLUTTER_VERSION_BUILD}")
|
||||
|
||||
# Disable Windows macros that collide with C++ standard library functions.
|
||||
target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
|
||||
|
||||
# Add dependency libraries and include directories. Add any application-specific
|
||||
# dependencies here.
|
||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
|
||||
target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
|
||||
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
# Run the Flutter tool portions of the build. This must not be removed.
|
||||
add_dependencies(${BINARY_NAME} flutter_assemble)
|
||||
121
windows/runner/Runner.rc
Normal file
121
windows/runner/Runner.rc
Normal file
@@ -0,0 +1,121 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#pragma code_page(65001)
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_APP_ICON ICON "resources\\app_icon.ico"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
#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
|
||||
#else
|
||||
#define VERSION_AS_NUMBER 1,0,0,0
|
||||
#endif
|
||||
|
||||
#if defined(FLUTTER_VERSION)
|
||||
#define VERSION_AS_STRING FLUTTER_VERSION
|
||||
#else
|
||||
#define VERSION_AS_STRING "1.0.0"
|
||||
#endif
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION_AS_NUMBER
|
||||
PRODUCTVERSION VERSION_AS_NUMBER
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904e4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "de.wger" "\0"
|
||||
VALUE "FileDescription", "wger" "\0"
|
||||
VALUE "FileVersion", VERSION_AS_STRING "\0"
|
||||
VALUE "InternalName", "wger" "\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2024 de.wger. All rights reserved." "\0"
|
||||
VALUE "OriginalFilename", "wger.exe" "\0"
|
||||
VALUE "ProductName", "wger" "\0"
|
||||
VALUE "ProductVersion", VERSION_AS_STRING "\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
71
windows/runner/flutter_window.cpp
Normal file
71
windows/runner/flutter_window.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "flutter_window.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "flutter/generated_plugin_registrant.h"
|
||||
|
||||
FlutterWindow::FlutterWindow(const flutter::DartProject& project)
|
||||
: project_(project) {}
|
||||
|
||||
FlutterWindow::~FlutterWindow() {}
|
||||
|
||||
bool FlutterWindow::OnCreate() {
|
||||
if (!Win32Window::OnCreate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RECT frame = GetClientArea();
|
||||
|
||||
// The size here must match the window dimensions to avoid unnecessary surface
|
||||
// creation / destruction in the startup path.
|
||||
flutter_controller_ = std::make_unique<flutter::FlutterViewController>(
|
||||
frame.right - frame.left, frame.bottom - frame.top, project_);
|
||||
// Ensure that basic setup of the controller was successful.
|
||||
if (!flutter_controller_->engine() || !flutter_controller_->view()) {
|
||||
return false;
|
||||
}
|
||||
RegisterPlugins(flutter_controller_->engine());
|
||||
SetChildContent(flutter_controller_->view()->GetNativeWindow());
|
||||
|
||||
flutter_controller_->engine()->SetNextFrameCallback([&]() {
|
||||
this->Show();
|
||||
});
|
||||
|
||||
// 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.
|
||||
flutter_controller_->ForceRedraw();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlutterWindow::OnDestroy() {
|
||||
if (flutter_controller_) {
|
||||
flutter_controller_ = nullptr;
|
||||
}
|
||||
|
||||
Win32Window::OnDestroy();
|
||||
}
|
||||
|
||||
LRESULT
|
||||
FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
|
||||
WPARAM const wparam,
|
||||
LPARAM const lparam) noexcept {
|
||||
// Give Flutter, including plugins, an opportunity to handle window messages.
|
||||
if (flutter_controller_) {
|
||||
std::optional<LRESULT> result =
|
||||
flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
|
||||
lparam);
|
||||
if (result) {
|
||||
return *result;
|
||||
}
|
||||
}
|
||||
|
||||
switch (message) {
|
||||
case WM_FONTCHANGE:
|
||||
flutter_controller_->engine()->ReloadSystemFonts();
|
||||
break;
|
||||
}
|
||||
|
||||
return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
|
||||
}
|
||||
33
windows/runner/flutter_window.h
Normal file
33
windows/runner/flutter_window.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef RUNNER_FLUTTER_WINDOW_H_
|
||||
#define RUNNER_FLUTTER_WINDOW_H_
|
||||
|
||||
#include <flutter/dart_project.h>
|
||||
#include <flutter/flutter_view_controller.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "win32_window.h"
|
||||
|
||||
// A window that does nothing but host a Flutter view.
|
||||
class FlutterWindow : public Win32Window {
|
||||
public:
|
||||
// Creates a new FlutterWindow hosting a Flutter view running |project|.
|
||||
explicit FlutterWindow(const flutter::DartProject& project);
|
||||
virtual ~FlutterWindow();
|
||||
|
||||
protected:
|
||||
// Win32Window:
|
||||
bool OnCreate() override;
|
||||
void OnDestroy() override;
|
||||
LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
|
||||
LPARAM const lparam) noexcept override;
|
||||
|
||||
private:
|
||||
// The project to run.
|
||||
flutter::DartProject project_;
|
||||
|
||||
// The Flutter instance hosted by this window.
|
||||
std::unique_ptr<flutter::FlutterViewController> flutter_controller_;
|
||||
};
|
||||
|
||||
#endif // RUNNER_FLUTTER_WINDOW_H_
|
||||
43
windows/runner/main.cpp
Normal file
43
windows/runner/main.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include <flutter/dart_project.h>
|
||||
#include <flutter/flutter_view_controller.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "flutter_window.h"
|
||||
#include "utils.h"
|
||||
|
||||
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
||||
_In_ wchar_t *command_line, _In_ int show_command) {
|
||||
// Attach to console when present (e.g., 'flutter run') or create a
|
||||
// new console when running with a debugger.
|
||||
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
|
||||
CreateAndAttachConsole();
|
||||
}
|
||||
|
||||
// Initialize COM, so that it is available for use in the library and/or
|
||||
// plugins.
|
||||
::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
|
||||
flutter::DartProject project(L"data");
|
||||
|
||||
std::vector<std::string> command_line_arguments =
|
||||
GetCommandLineArguments();
|
||||
|
||||
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
|
||||
|
||||
FlutterWindow window(project);
|
||||
Win32Window::Point origin(10, 10);
|
||||
Win32Window::Size size(1280, 720);
|
||||
if (!window.Create(L"wger", origin, size)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
window.SetQuitOnClose(true);
|
||||
|
||||
::MSG msg;
|
||||
while (::GetMessage(&msg, nullptr, 0, 0)) {
|
||||
::TranslateMessage(&msg);
|
||||
::DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
::CoUninitialize();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
16
windows/runner/resource.h
Normal file
16
windows/runner/resource.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by Runner.rc
|
||||
//
|
||||
#define IDI_APP_ICON 101
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
BIN
windows/runner/resources/app_icon.ico
Normal file
BIN
windows/runner/resources/app_icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
20
windows/runner/runner.exe.manifest
Normal file
20
windows/runner/runner.exe.manifest
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 10 and Windows 11 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
<!-- Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<!-- Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<!-- Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
65
windows/runner/utils.cpp
Normal file
65
windows/runner/utils.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include <flutter_windows.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void CreateAndAttachConsole() {
|
||||
if (::AllocConsole()) {
|
||||
FILE *unused;
|
||||
if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
|
||||
_dup2(_fileno(stdout), 1);
|
||||
}
|
||||
if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
|
||||
_dup2(_fileno(stdout), 2);
|
||||
}
|
||||
std::ios::sync_with_stdio();
|
||||
FlutterDesktopResyncOutputStreams();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> GetCommandLineArguments() {
|
||||
// Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
|
||||
int argc;
|
||||
wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
|
||||
if (argv == nullptr) {
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
std::vector<std::string> command_line_arguments;
|
||||
|
||||
// Skip the first argument as it's the binary name.
|
||||
for (int i = 1; i < argc; i++) {
|
||||
command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
|
||||
}
|
||||
|
||||
::LocalFree(argv);
|
||||
|
||||
return command_line_arguments;
|
||||
}
|
||||
|
||||
std::string Utf8FromUtf16(const wchar_t* utf16_string) {
|
||||
if (utf16_string == nullptr) {
|
||||
return std::string();
|
||||
}
|
||||
unsigned int target_length = ::WideCharToMultiByte(
|
||||
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
|
||||
-1, nullptr, 0, nullptr, nullptr)
|
||||
-1; // remove the trailing null character
|
||||
int input_length = (int)wcslen(utf16_string);
|
||||
std::string utf8_string;
|
||||
if (target_length == 0 || target_length > utf8_string.max_size()) {
|
||||
return utf8_string;
|
||||
}
|
||||
utf8_string.resize(target_length);
|
||||
int converted_length = ::WideCharToMultiByte(
|
||||
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
|
||||
input_length, utf8_string.data(), target_length, nullptr, nullptr);
|
||||
if (converted_length == 0) {
|
||||
return std::string();
|
||||
}
|
||||
return utf8_string;
|
||||
}
|
||||
19
windows/runner/utils.h
Normal file
19
windows/runner/utils.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef RUNNER_UTILS_H_
|
||||
#define RUNNER_UTILS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Creates a console for the process, and redirects stdout and stderr to
|
||||
// it for both the runner and the Flutter library.
|
||||
void CreateAndAttachConsole();
|
||||
|
||||
// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
|
||||
// encoded in UTF-8. Returns an empty std::string on failure.
|
||||
std::string Utf8FromUtf16(const wchar_t* utf16_string);
|
||||
|
||||
// Gets the command line arguments passed in as a std::vector<std::string>,
|
||||
// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.
|
||||
std::vector<std::string> GetCommandLineArguments();
|
||||
|
||||
#endif // RUNNER_UTILS_H_
|
||||
288
windows/runner/win32_window.cpp
Normal file
288
windows/runner/win32_window.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
#include "win32_window.h"
|
||||
|
||||
#include <dwmapi.h>
|
||||
#include <flutter_windows.h>
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
namespace {
|
||||
|
||||
/// Window attribute that enables dark mode window decorations.
|
||||
///
|
||||
/// Redefined in case the developer's machine has a Windows SDK older than
|
||||
/// version 10.0.22000.0.
|
||||
/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
|
||||
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
|
||||
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
|
||||
#endif
|
||||
|
||||
constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
|
||||
|
||||
/// Registry key for app theme preference.
|
||||
///
|
||||
/// A value of 0 indicates apps should use dark mode. A non-zero or missing
|
||||
/// value indicates apps should use light mode.
|
||||
constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
|
||||
constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
|
||||
|
||||
// The number of Win32Window objects that currently exist.
|
||||
static int g_active_window_count = 0;
|
||||
|
||||
using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
|
||||
|
||||
// Scale helper to convert logical scaler values to physical using passed in
|
||||
// scale factor
|
||||
int Scale(int source, double scale_factor) {
|
||||
return static_cast<int>(source * scale_factor);
|
||||
}
|
||||
|
||||
// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
|
||||
// This API is only needed for PerMonitor V1 awareness mode.
|
||||
void EnableFullDpiSupportIfAvailable(HWND hwnd) {
|
||||
HMODULE user32_module = LoadLibraryA("User32.dll");
|
||||
if (!user32_module) {
|
||||
return;
|
||||
}
|
||||
auto enable_non_client_dpi_scaling =
|
||||
reinterpret_cast<EnableNonClientDpiScaling*>(
|
||||
GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
|
||||
if (enable_non_client_dpi_scaling != nullptr) {
|
||||
enable_non_client_dpi_scaling(hwnd);
|
||||
}
|
||||
FreeLibrary(user32_module);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Manages the Win32Window's window class registration.
|
||||
class WindowClassRegistrar {
|
||||
public:
|
||||
~WindowClassRegistrar() = default;
|
||||
|
||||
// Returns the singleton registrar instance.
|
||||
static WindowClassRegistrar* GetInstance() {
|
||||
if (!instance_) {
|
||||
instance_ = new WindowClassRegistrar();
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
// Returns the name of the window class, registering the class if it hasn't
|
||||
// previously been registered.
|
||||
const wchar_t* GetWindowClass();
|
||||
|
||||
// Unregisters the window class. Should only be called if there are no
|
||||
// instances of the window.
|
||||
void UnregisterWindowClass();
|
||||
|
||||
private:
|
||||
WindowClassRegistrar() = default;
|
||||
|
||||
static WindowClassRegistrar* instance_;
|
||||
|
||||
bool class_registered_ = false;
|
||||
};
|
||||
|
||||
WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;
|
||||
|
||||
const wchar_t* WindowClassRegistrar::GetWindowClass() {
|
||||
if (!class_registered_) {
|
||||
WNDCLASS window_class{};
|
||||
window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
window_class.lpszClassName = kWindowClassName;
|
||||
window_class.style = CS_HREDRAW | CS_VREDRAW;
|
||||
window_class.cbClsExtra = 0;
|
||||
window_class.cbWndExtra = 0;
|
||||
window_class.hInstance = GetModuleHandle(nullptr);
|
||||
window_class.hIcon =
|
||||
LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));
|
||||
window_class.hbrBackground = 0;
|
||||
window_class.lpszMenuName = nullptr;
|
||||
window_class.lpfnWndProc = Win32Window::WndProc;
|
||||
RegisterClass(&window_class);
|
||||
class_registered_ = true;
|
||||
}
|
||||
return kWindowClassName;
|
||||
}
|
||||
|
||||
void WindowClassRegistrar::UnregisterWindowClass() {
|
||||
UnregisterClass(kWindowClassName, nullptr);
|
||||
class_registered_ = false;
|
||||
}
|
||||
|
||||
Win32Window::Win32Window() {
|
||||
++g_active_window_count;
|
||||
}
|
||||
|
||||
Win32Window::~Win32Window() {
|
||||
--g_active_window_count;
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool Win32Window::Create(const std::wstring& title,
|
||||
const Point& origin,
|
||||
const Size& size) {
|
||||
Destroy();
|
||||
|
||||
const wchar_t* window_class =
|
||||
WindowClassRegistrar::GetInstance()->GetWindowClass();
|
||||
|
||||
const POINT target_point = {static_cast<LONG>(origin.x),
|
||||
static_cast<LONG>(origin.y)};
|
||||
HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
|
||||
UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
|
||||
double scale_factor = dpi / 96.0;
|
||||
|
||||
HWND window = CreateWindow(
|
||||
window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
|
||||
Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
|
||||
Scale(size.width, scale_factor), Scale(size.height, scale_factor),
|
||||
nullptr, nullptr, GetModuleHandle(nullptr), this);
|
||||
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UpdateTheme(window);
|
||||
|
||||
return OnCreate();
|
||||
}
|
||||
|
||||
bool Win32Window::Show() {
|
||||
return ShowWindow(window_handle_, SW_SHOWNORMAL);
|
||||
}
|
||||
|
||||
// static
|
||||
LRESULT CALLBACK Win32Window::WndProc(HWND const window,
|
||||
UINT const message,
|
||||
WPARAM const wparam,
|
||||
LPARAM const lparam) noexcept {
|
||||
if (message == WM_NCCREATE) {
|
||||
auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
|
||||
SetWindowLongPtr(window, GWLP_USERDATA,
|
||||
reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));
|
||||
|
||||
auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);
|
||||
EnableFullDpiSupportIfAvailable(window);
|
||||
that->window_handle_ = window;
|
||||
} else if (Win32Window* that = GetThisFromHandle(window)) {
|
||||
return that->MessageHandler(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
return DefWindowProc(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
LRESULT
|
||||
Win32Window::MessageHandler(HWND hwnd,
|
||||
UINT const message,
|
||||
WPARAM const wparam,
|
||||
LPARAM const lparam) noexcept {
|
||||
switch (message) {
|
||||
case WM_DESTROY:
|
||||
window_handle_ = nullptr;
|
||||
Destroy();
|
||||
if (quit_on_close_) {
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_DPICHANGED: {
|
||||
auto newRectSize = reinterpret_cast<RECT*>(lparam);
|
||||
LONG newWidth = newRectSize->right - newRectSize->left;
|
||||
LONG newHeight = newRectSize->bottom - newRectSize->top;
|
||||
|
||||
SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
|
||||
newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case WM_SIZE: {
|
||||
RECT rect = GetClientArea();
|
||||
if (child_content_ != nullptr) {
|
||||
// Size and position the child window.
|
||||
MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
|
||||
rect.bottom - rect.top, TRUE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_ACTIVATE:
|
||||
if (child_content_ != nullptr) {
|
||||
SetFocus(child_content_);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_DWMCOLORIZATIONCOLORCHANGED:
|
||||
UpdateTheme(hwnd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProc(window_handle_, message, wparam, lparam);
|
||||
}
|
||||
|
||||
void Win32Window::Destroy() {
|
||||
OnDestroy();
|
||||
|
||||
if (window_handle_) {
|
||||
DestroyWindow(window_handle_);
|
||||
window_handle_ = nullptr;
|
||||
}
|
||||
if (g_active_window_count == 0) {
|
||||
WindowClassRegistrar::GetInstance()->UnregisterWindowClass();
|
||||
}
|
||||
}
|
||||
|
||||
Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
|
||||
return reinterpret_cast<Win32Window*>(
|
||||
GetWindowLongPtr(window, GWLP_USERDATA));
|
||||
}
|
||||
|
||||
void Win32Window::SetChildContent(HWND content) {
|
||||
child_content_ = content;
|
||||
SetParent(content, window_handle_);
|
||||
RECT frame = GetClientArea();
|
||||
|
||||
MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
|
||||
frame.bottom - frame.top, true);
|
||||
|
||||
SetFocus(child_content_);
|
||||
}
|
||||
|
||||
RECT Win32Window::GetClientArea() {
|
||||
RECT frame;
|
||||
GetClientRect(window_handle_, &frame);
|
||||
return frame;
|
||||
}
|
||||
|
||||
HWND Win32Window::GetHandle() {
|
||||
return window_handle_;
|
||||
}
|
||||
|
||||
void Win32Window::SetQuitOnClose(bool quit_on_close) {
|
||||
quit_on_close_ = quit_on_close;
|
||||
}
|
||||
|
||||
bool Win32Window::OnCreate() {
|
||||
// No-op; provided for subclasses.
|
||||
return true;
|
||||
}
|
||||
|
||||
void Win32Window::OnDestroy() {
|
||||
// No-op; provided for subclasses.
|
||||
}
|
||||
|
||||
void Win32Window::UpdateTheme(HWND const window) {
|
||||
DWORD light_mode;
|
||||
DWORD light_mode_size = sizeof(light_mode);
|
||||
LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
|
||||
kGetPreferredBrightnessRegValue,
|
||||
RRF_RT_REG_DWORD, nullptr, &light_mode,
|
||||
&light_mode_size);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
BOOL enable_dark_mode = light_mode == 0;
|
||||
DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
|
||||
&enable_dark_mode, sizeof(enable_dark_mode));
|
||||
}
|
||||
}
|
||||
102
windows/runner/win32_window.h
Normal file
102
windows/runner/win32_window.h
Normal file
@@ -0,0 +1,102 @@
|
||||
#ifndef RUNNER_WIN32_WINDOW_H_
|
||||
#define RUNNER_WIN32_WINDOW_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
// A class abstraction for a high DPI-aware Win32 Window. Intended to be
|
||||
// inherited from by classes that wish to specialize with custom
|
||||
// rendering and input handling
|
||||
class Win32Window {
|
||||
public:
|
||||
struct Point {
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
Point(unsigned int x, unsigned int y) : x(x), y(y) {}
|
||||
};
|
||||
|
||||
struct Size {
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
Size(unsigned int width, unsigned int height)
|
||||
: width(width), height(height) {}
|
||||
};
|
||||
|
||||
Win32Window();
|
||||
virtual ~Win32Window();
|
||||
|
||||
// Creates a win32 window with |title| that is positioned and sized using
|
||||
// |origin| and |size|. New windows are created on the default monitor. Window
|
||||
// sizes are specified to the OS in physical pixels, hence to ensure a
|
||||
// consistent size this function will scale the inputted width and height as
|
||||
// as appropriate for the default monitor. The window is invisible until
|
||||
// |Show| is called. Returns true if the window was created successfully.
|
||||
bool Create(const std::wstring& title, const Point& origin, const Size& size);
|
||||
|
||||
// Show the current window. Returns true if the window was successfully shown.
|
||||
bool Show();
|
||||
|
||||
// Release OS resources associated with window.
|
||||
void Destroy();
|
||||
|
||||
// Inserts |content| into the window tree.
|
||||
void SetChildContent(HWND content);
|
||||
|
||||
// Returns the backing Window handle to enable clients to set icon and other
|
||||
// window properties. Returns nullptr if the window has been destroyed.
|
||||
HWND GetHandle();
|
||||
|
||||
// If true, closing this window will quit the application.
|
||||
void SetQuitOnClose(bool quit_on_close);
|
||||
|
||||
// Return a RECT representing the bounds of the current client area.
|
||||
RECT GetClientArea();
|
||||
|
||||
protected:
|
||||
// Processes and route salient window messages for mouse handling,
|
||||
// size change and DPI. Delegates handling of these to member overloads that
|
||||
// inheriting classes can handle.
|
||||
virtual LRESULT MessageHandler(HWND window,
|
||||
UINT const message,
|
||||
WPARAM const wparam,
|
||||
LPARAM const lparam) noexcept;
|
||||
|
||||
// Called when CreateAndShow is called, allowing subclass window-related
|
||||
// setup. Subclasses should return false if setup fails.
|
||||
virtual bool OnCreate();
|
||||
|
||||
// Called when Destroy is called.
|
||||
virtual void OnDestroy();
|
||||
|
||||
private:
|
||||
friend class WindowClassRegistrar;
|
||||
|
||||
// OS callback called by message pump. Handles the WM_NCCREATE message which
|
||||
// is passed when the non-client area is being created and enables automatic
|
||||
// non-client DPI scaling so that the non-client area automatically
|
||||
// responds to changes in DPI. All other messages are handled by
|
||||
// MessageHandler.
|
||||
static LRESULT CALLBACK WndProc(HWND const window,
|
||||
UINT const message,
|
||||
WPARAM const wparam,
|
||||
LPARAM const lparam) noexcept;
|
||||
|
||||
// Retrieves a class instance pointer for |window|
|
||||
static Win32Window* GetThisFromHandle(HWND const window) noexcept;
|
||||
|
||||
// Update the window frame's theme to match the system theme.
|
||||
static void UpdateTheme(HWND const window);
|
||||
|
||||
bool quit_on_close_ = false;
|
||||
|
||||
// window handle for top level window.
|
||||
HWND window_handle_ = nullptr;
|
||||
|
||||
// window handle for hosted content.
|
||||
HWND child_content_ = nullptr;
|
||||
};
|
||||
|
||||
#endif // RUNNER_WIN32_WINDOW_H_
|
||||
Reference in New Issue
Block a user