diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index b5c29eca..00000000 --- a/.cirrus.yml +++ /dev/null @@ -1,112 +0,0 @@ -timeout_in: 30m -env: - FLUTTER_CHANNEL: stable - FLUTTER_VERSION: v1.12.13+hotfix.5 - DOCKER_VERSION: v1.12.13-hotfix.5 # docker tags cannot have plus - -task: - # this task should fail fast or rely on 'depends_on' for all other tasks - name: Static analysis, formatting, and unit tests - container: - image: cirrusci/flutter:$DOCKER_VERSION - pub_cache: - folder: ~/.pub-cache - activate_coverage_script: pub global activate coverage - tests_script: ./scripts/runTests.sh - -task: - name: Integration Tests for $app_arch (Linux) - # don't run for PRs - only_if: $CIRRUS_PR == '' - skip: '!changesInclude(".cirrus.yml", "$app_arch/*", "$app_arch/**/*")' - env: - EMULATOR_API_LEVEL: 28 - ANDROID_ABI: "default;x86" - matrix: - app_arch: bloc_flutter - app_arch: bloc_library - app_arch: built_redux - app_arch: firestore_redux - app_arch: frideos_library - app_arch: inherited_widget - app_arch: mobx - app_arch: mvc - app_arch: mvi_flutter - app_arch: mvu - app_arch: change_notifier_provider - app_arch: redux - app_arch: scoped_model - app_arch: simple_bloc_flutter - app_arch: vanilla - app_arch: states_rebuilder - container: - image: cirrusci/flutter:$DOCKER_VERSION - cpu: 4 - memory: 10G - kvm: true - fix_kvm_script: sudo chown cirrus:cirrus /dev/kvm - install_images_script: sdkmanager "system-images;android-$EMULATOR_API_LEVEL;$ANDROID_ABI" - create_device_script: - echo no | avdmanager create avd --force -n test -k "system-images;android-$EMULATOR_API_LEVEL;$ANDROID_ABI" - start_emulator_background_script: - $ANDROID_HOME/emulator/emulator-headless -verbose -avd test -no-audio -no-window - pub_cache: - folder: ~/.pub-cache - wait_for_emulator_script: - - ./scripts/android-wait-for-emulator.sh -# - adb shell input keyevent 82 - doctor_script: flutter doctor -v - devices_script: flutter devices - ci_script: ./scripts/ci.sh ./$app_arch || ./scripts/ci.sh ./$app_arch - -task: - name: Integration Tests for $app_arch (macOS) - # don't run for PRs - only_if: $CIRRUS_PR == '' - skip: '!changesInclude(".cirrus.yml", "$app_arch/*", "$app_arch/**/*")' - env: - matrix: - app_arch: bloc_flutter - app_arch: bloc_library - app_arch: built_redux - app_arch: firestore_redux - app_arch: frideos_library - app_arch: inherited_widget - app_arch: mvc - app_arch: mvi_flutter - app_arch: mvu - app_arch: change_notifier_provider - app_arch: redux - app_arch: scoped_model - app_arch: simple_bloc_flutter - app_arch: vanilla - app_arch: states_rebuilder - osx_instance: - image: mojave-xcode-11.2.1-flutter - simulator_script: - - xcrun simctl list devicetypes - - xcrun simctl list runtimes - # create simulator - - udid=$(xcrun simctl create "iPhone X" com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-2) - # boot simulator - - xcrun simctl boot $udid - pin_flutter_script: -# - sudo gem install cocoapods # missing from mojave-xcode-11.2.1-flutter (not found) - - flutter --version - # pin to ${FLUTTER_VERSION} - - wget --quiet --output-document=flutter.zip https://storage.googleapis.com/flutter_infra/releases/${FLUTTER_CHANNEL}/macos/flutter_macos_${FLUTTER_VERSION}-${FLUTTER_CHANNEL}.zip && unzip -qq flutter.zip > /dev/null && rm flutter.zip - - export PATH="$PATH":"$HOME/.pub-cache/bin" - - export PATH=$PWD/flutter/bin:$PWD/flutter/bin/cache/dart-sdk/bin:$PATH - - flutter --version - doctor_script: - - export PATH="$PATH":"$HOME/.pub-cache/bin" - - export PATH=$PWD/flutter/bin:$PWD/flutter/bin/cache/dart-sdk/bin:$PATH - - flutter doctor -v - devices_script: - - export PATH="$PATH":"$HOME/.pub-cache/bin" - - export PATH=$PWD/flutter/bin:$PWD/flutter/bin/cache/dart-sdk/bin:$PATH - - flutter devices - ci_script: - - export PATH="$PATH":"$HOME/.pub-cache/bin" - - export PATH=$PWD/flutter/bin:$PWD/flutter/bin/cache/dart-sdk/bin:$PATH - - ./scripts/ci.sh ./$app_arch || ./scripts/ci.sh ./$app_arch diff --git a/.fvmrc b/.fvmrc new file mode 100644 index 00000000..2bb4682a --- /dev/null +++ b/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "3.35.2" +} \ No newline at end of file diff --git a/.github/actions/dart_analysis_and_tests/action.yml b/.github/actions/dart_analysis_and_tests/action.yml new file mode 100644 index 00000000..5120e7f3 --- /dev/null +++ b/.github/actions/dart_analysis_and_tests/action.yml @@ -0,0 +1,43 @@ +name: "Validate" +description: "Runs lint, format, and test on an app" +inputs: + working-directory: + description: "Directory to run validation in" + required: true + +runs: + using: "composite" + steps: + - name: Set up flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + + - name: Get dependencies + shell: bash + run: dart pub get + working-directory: ${{ inputs.working-directory }} + + - name: Check dart formatting + shell: bash + run: dart format -o none --set-exit-if-changed . + working-directory: ${{ inputs.working-directory }} + + - name: Check dart analysis + shell: bash + run: dart analyze --fatal-infos --fatal-warnings . + working-directory: ${{ inputs.working-directory }} + + - name: Run unit tests and prepare coverage + shell: bash + run: | + dart pub global activate coverage + dart run test --coverage=coverage + dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=lib + # Extract directory name for artifact naming + echo "DIR_NAME=$(basename "${{ inputs.working-directory }}")" >> $GITHUB_ENV + working-directory: ${{ inputs.working-directory }} + + - name: Upload coverage artifact + uses: actions/upload-artifact@v4 + with: + name: coverage-lcov-${{ env.DIR_NAME }} + path: ${{ inputs.working-directory }}/coverage/lcov.info diff --git a/.github/actions/flutter_analysis_test_build/action.yml b/.github/actions/flutter_analysis_test_build/action.yml new file mode 100644 index 00000000..188e03a1 --- /dev/null +++ b/.github/actions/flutter_analysis_test_build/action.yml @@ -0,0 +1,93 @@ +name: "Validate" +description: "Runs lint, format, and test on an app" +inputs: + working-directory: + description: "Directory to run validation in" + required: true + run-integration-tests: + description: "Run integration tests" + required: false + default: "true" + deploy-to-netlify: + description: "Deploy to Netlify" + required: true + default: "false" + netlify-auth-token: + description: "Netlify auth token" + required: true + netlify-site-id: + description: "Netlify site id" + required: true +runs: + using: "composite" + steps: + - name: Set up flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + + - name: Get dependencies + shell: bash + run: flutter pub get + working-directory: ${{ inputs.working-directory }} + + - name: Check dart formatting + shell: bash + run: dart format -o none --set-exit-if-changed . + working-directory: ${{ inputs.working-directory }} + + - name: Check dart analysis + shell: bash + run: dart analyze --fatal-infos --fatal-warnings . + working-directory: ${{ inputs.working-directory }} + + - name: Run unit tests and prepare coverage + shell: bash + if: '[ -d "${{ inputs.working-directory }}/test" ]' + run: | + flutter test --coverage + # Extract directory name for artifact naming + echo "DIR_NAME=$(basename "${{ inputs.working-directory }}")" >> $GITHUB_ENV + working-directory: ${{ inputs.working-directory }} + + - name: Upload coverage artifact + uses: actions/upload-artifact@v4 + with: + name: coverage-lcov-${{ env.DIR_NAME }} + path: ${{ inputs.working-directory }}/coverage/lcov.info + + - name: Run linux integration tests + if: ${{ inputs.run-integration-tests != 'false' }} + shell: bash + run: | + sudo apt-get update + sudo apt-get install \ + clang \ + cmake \ + git \ + ninja-build \ + pkg-config \ + libgtk-3-dev \ + liblzma-dev \ + libstdc++-12-dev \ + libglu1-mesa \ + xvfb + export DISPLAY=:99 # Set display for Xvfb + xvfb-run -a flutter test integration_test/app_test.dart -d linux + working-directory: ${{ inputs.working-directory }} + + - name: Build web app + if: ${{ inputs.deploy-to-netlify != 'false' }} + shell: bash + run: | + flutter build web --wasm + working-directory: ${{ inputs.working-directory }} + + - name: Deploy to Netlify + if: ${{ inputs.deploy-to-netlify != 'false' }} + uses: nwtgck/actions-netlify@v3.0 + with: + publish-dir: ${{ inputs.working-directory }}/build/web + production-deploy: true + deploy-message: "Deploy from GitHub Actions" + env: + NETLIFY_AUTH_TOKEN: ${{ inputs.netlify-auth-token }} + NETLIFY_SITE_ID: ${{ inputs.netlify-site-id }} diff --git a/.github/workflows/analyze_test_build.yml b/.github/workflows/analyze_test_build.yml new file mode 100644 index 00000000..a5a90740 --- /dev/null +++ b/.github/workflows/analyze_test_build.yml @@ -0,0 +1,295 @@ +name: Static Analysis, Run Tests and Build Web Apps + +on: + pull_request: + push: + branches: + - main + +jobs: + bloc_flutter: + name: bloc_flutter + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./bloc_flutter + deploy-to-netlify: ${{ github.ref_name == 'main' }} + netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify-site-id: ${{ secrets.BLOC_FLUTTER_NETLIFY_SITE_ID }} + bloc_library: + name: bloc_library + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./bloc_library + deploy-to-netlify: ${{ github.ref_name == 'main' }} + netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify-site-id: ${{ secrets.BLOC_LIBRARY_NETLIFY_SITE_ID }} + blocs: + name: blocs + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/dart_analysis_and_tests + with: + working-directory: ./blocs + change_notifier_provider: + name: change_notifier_provider + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./change_notifier_provider + deploy-to-netlify: ${{ github.ref_name == 'main' }} + netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify-site-id: ${{ secrets.CHANGE_NOTIFIER_PROVIDER_NETLIFY_SITE_ID }} + freezed_provider_value_notifier: + name: freezed_provider_value_notifier + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./freezed_provider_value_notifier + deploy-to-netlify: ${{ github.ref_name == 'main' }} + netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify-site-id: ${{ secrets.FREEZED_PROVIDER_VALUE_NOTIFIER_NETLIFY_SITE_ID }} + inherited_widget: + name: inherited_widget + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./inherited_widget + deploy-to-netlify: ${{ github.ref_name == 'main' }} + netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify-site-id: ${{ secrets.INHERITED_WIDGET_NETLIFY_SITE_ID }} + mobx: + name: mobx + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./mobx + deploy-to-netlify: ${{ github.ref_name == 'main' }} + netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify-site-id: ${{ secrets.MOBX_NETLIFY_SITE_ID }} + mvi_base: + name: mvi_base + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/dart_analysis_and_tests + with: + working-directory: ./mvi_base + mvi_flutter: + name: mvi_flutter + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./mvi_flutter + deploy-to-netlify: ${{ github.ref_name == 'main' }} + netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify-site-id: ${{ secrets.MVI_NETLIFY_SITE_ID }} + redux: + name: redux + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./redux + deploy-to-netlify: ${{ github.ref_name == 'main' }} + netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify-site-id: ${{ secrets.REDUX_NETLIFY_SITE_ID }} + scoped_model: + name: scoped_model + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./scoped_model + deploy-to-netlify: ${{ github.ref_name == 'main' }} + netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify-site-id: ${{ secrets.SCOPED_MODEL_NETLIFY_SITE_IT }} + signals: + name: signals + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./signals + deploy-to-netlify: ${{ github.ref_name == 'main' }} + netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify-site-id: ${{ secrets.SIGNALS_NETLIFY_SITE_ID }} + simple_bloc_flutter: + name: simple_bloc_flutter + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./simple_bloc_flutter + deploy-to-netlify: ${{ github.ref_name == 'main' }} + netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify-site-id: ${{ secrets.SIMPLE_BLOC_NETLIFY_SITE_ID }} + simple_blocs: + name: simple_blocs + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/dart_analysis_and_tests + with: + working-directory: ./simple_blocs + todos_repository_local_storage: + name: todos_repository_local_storage + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./todos_repository_local_storage + run-integration-tests: false + vanilla: + name: vanilla + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Static Analysis, Run Tests, and Build web app + uses: ./.github/actions/flutter_analysis_test_build + with: + working-directory: ./vanilla + deploy-to-netlify: ${{ github.ref_name == 'main' }} + netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify-site-id: ${{ secrets.VANILLA_NETLIFY_SITE_ID }} + combine_and_upload_coverage: + name: Combine and Upload Coverage + runs-on: ubuntu-latest + needs: + - bloc_flutter + - bloc_library + - blocs + - change_notifier_provider + - freezed_provider_value_notifier + - inherited_widget + - mobx + - mvi_base + - mvi_flutter + - redux + - scoped_model + - signals + - simple_bloc_flutter + - simple_blocs + - todos_repository_local_storage + - vanilla + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Download coverage artifacts + uses: actions/download-artifact@v4 + with: + path: . + - name: Combine coverage files + run: | + combineCoverage() { + local artifact_dir=$1 + local repo_dir=$2 + # Extract the package directory path from the artifact name + # coverage-lcov-vanilla -> ./vanilla + local package_name=$(basename "$artifact_dir") + local package_dir="./${package_name#coverage-lcov-}" + escapedPath="$(echo $package_dir | sed 's/\//\\\//g')" + + if [[ -d "$artifact_dir" ]]; then + # Find the lcov.info file in the artifact directory + for lcov_file in "$artifact_dir"/*.info; do + if [[ -f "$lcov_file" ]]; then + echo "Combining coverage from $package_dir" + # combine line coverage info from package tests to a common file + sed "s/^SF:lib/SF:$escapedPath\/lib/g" "$lcov_file" >> "$repo_dir/lcov.info" + break + fi + done + fi + } + + # Initialize the combined coverage file + touch lcov.info + + # Combine coverage from all downloaded artifacts + for artifact_dir in coverage-lcov-*/; do + if [[ -d "$artifact_dir" ]]; then + combineCoverage "$artifact_dir" "." + fi + done + + echo "Combined coverage file created:" + ls -la lcov.info + echo "First few lines of combined coverage:" + head -10 lcov.info + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + files: ./lcov.info + disable_search: true + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index 34d26916..8bb94fa7 100644 --- a/.gitignore +++ b/.gitignore @@ -91,3 +91,9 @@ lcov.info !**/*/ios/**/default.pbxuser !**/*/ios/**/default.perspectivev3 **/*/generated_plugin_registrant.dart + +.vscode/ + +# FVM Version Cache +.fvm/ +.cursor/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d09dd464..00000000 --- a/.travis.yml +++ /dev/null @@ -1,352 +0,0 @@ -language: generic -env: - global: - - FLUTTER_CHANNEL=stable - - FLUTTER_VERSION=1.12.13+hotfix.5-${FLUTTER_CHANNEL} - - API=28 - - ABI=x86 - - GOO=default - - ANDROID_TOOLS=4333796 # android-28 - - ANDROID_HOME=${HOME}/android-sdk - - GRAVIS="https://raw.githubusercontent.com/DanySK/Gravis-CI/master/" - - JDK="1.8" # the JDK used for running tests - - TOOLS=${ANDROID_HOME}/tools - # PATH order is incredibly important. e.g. the 'emulator' script exists in more than one place! - - PATH=${ANDROID_HOME}:${ANDROID_HOME}/emulator:${TOOLS}:${TOOLS}/bin:${ANDROID_HOME}/platform-tools:${PATH} - - FLUTTER_HOME=${HOME}/flutter - - PATH=${HOME}/.pub-cache/bin:${PATH} - - PATH=${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart-sdk/bin:${PATH} - -jobs: - include: - - - stage: Static analysis, formatting, and unit tests - language: generic - dist: bionic - os: linux - env: All unit and widget tests - before_script: - - sudo apt-get install -y --no-install-recommends lib32stdc++6 libstdc++6 > /dev/null - - # install pre-compiled flutter - - wget --quiet --output-document=flutter.tar.xz https://storage.googleapis.com/flutter_infra/releases/${FLUTTER_CHANNEL}/linux/flutter_linux_v${FLUTTER_VERSION}.tar.xz && tar xf flutter.tar.xz > /dev/null && rm flutter.tar.xz - - export PATH="$PATH":"$HOME/.pub-cache/bin" - - export PATH=$PWD/flutter/bin:$PWD/flutter/bin/cache/dart-sdk/bin:$PATH - - flutter doctor -v - - pub global activate coverage - script: ./scripts/runTests.sh - after_success: bash <(curl -s https://codecov.io/bash) -f lcov.info - cache: - directories: - - $HOME/.pub-cache - - - &integration-test - stage: Testing - dist: bionic - language: generic - os: linux - env: bloc_flutter_android - # Run integration tests on android - before_install: &before_install_linux - - java -version - - # Set up KVM - - sudo apt-get -y --no-install-recommends install bridge-utils libpulse0 libvirt-bin qemu-kvm virtinst ubuntu-vm-builder > /dev/null - # add travis user to groups - - sudo adduser $USER libvirt - - sudo adduser $USER kvm - - # Set up JDK 8 for Android SDK - - curl "${GRAVIS}.install-jdk-travis.sh" --output ~/.install-jdk-travis.sh - - export TARGET_JDK="${JDK}" - - JDK="1.8" # used when running sdkmanager - - source ~/.install-jdk-travis.sh - - # Set up Android SDK - - wget -q "https://dl.google.com/android/repository/sdk-tools-linux-$ANDROID_TOOLS.zip" -O android-sdk-tools.zip - - unzip -q android-sdk-tools.zip -d ${ANDROID_HOME} - - rm android-sdk-tools.zip - - # Avoid harmless sdkmanager warning - - mkdir ~/.android - - echo 'count=0' > ~/.android/repositories.cfg - - # Accept licenses before installing components, no need to echo y for each component - - yes | sdkmanager --licenses >/dev/null - - # Download SDK tools - - sdkmanager "platform-tools" >/dev/null - - sdkmanager "tools" >/dev/null # A second time per Travis docs, gets latest versions - - sdkmanager "build-tools;28.0.3" >/dev/null # Implicit gradle dependency - gradle drives changes - - sdkmanager "platforms;android-$API" >/dev/null # We need the API of the emulator we will run - - sdkmanager "platforms;android-28" >/dev/null # We need the API of the current compileSdkVersion from gradle.properties - - - - sdkmanager "emulator" >/dev/null - - | - if [[ $ABI =~ "arm" ]]; then - # Download a pinned version of the emulator since default version can cause issues - ${ANDROID_HOME}/emulator/emulator -version - emulator_version=5264690 # 29.2.1.0 (build_id 5889189) ==> 28.0.23.0 (build_id 5264690) - # sudo apt-get install -y libunwind8 libc++1 - curl -fo emulator.zip "https://dl.google.com/android/repository/emulator-linux-$emulator_version.zip" - rm -rf "${ANDROID_HOME}/emulator" - unzip -q emulator.zip -d "${ANDROID_HOME}" - rm -f emulator.zip - # install build tools and platforms for arm (to allow emulator to run) - sdkmanager "build-tools;25.0.2" "platforms;android-25" > /dev/null - fi - - ${ANDROID_HOME}/emulator/emulator -version - - - sdkmanager "extras;android;m2repository" >/dev/null - - sdkmanager "system-images;android-$API;$GOO;$ABI" >/dev/null # install system images for emulator - - # Create an Android emulator - # - echo no | avdmanager --verbose create avd --force -n test -k "system-images;android-$API;$GOO;$ABI" -c 10M - - echo no | avdmanager --verbose create avd --force -n test -k "system-images;android-$API;$GOO;$ABI" - # - EMU_PARAMS=" - # -verbose - # -no-snapshot - # -no-window - # -no-audio - # -no-boot-anim - # -camera-back none - # -camera-front none - # -selinux permissive - # -qemu -m 2048" - - EMU_PARAMS=" - -avd test - -verbose - -no-window - -no-audio - " - - EMU_COMMAND="emulator" - - | - if [[ $ABI =~ "x86" ]]; then - EMU_COMMAND="emulator" - else - # emulate graphics if running on ARM - EMU_PARAMS="${EMU_PARAMS} -gpu swiftshader" - fi - # This double "sudo" monstrosity is used to have Travis execute the - # emulator with its new group permissions and help preserve the rule - # of least privilege. - - sudo -E sudo -u $USER -E bash -c "${ANDROID_HOME}/emulator/${EMU_COMMAND} ${EMU_PARAMS} &" - - # install flutter (while emulator is starting) - - sudo apt-get install -y --no-install-recommends lib32stdc++6 libstdc++6 > /dev/null - - wget --quiet --output-document=flutter.tar.xz https://storage.googleapis.com/flutter_infra/releases/${FLUTTER_CHANNEL}/linux/flutter_linux_v${FLUTTER_VERSION}.tar.xz - - tar xf flutter.tar.xz -C $(dirname ${FLUTTER_HOME}) - - rm flutter.tar.xz - - # Switch back to our target JDK version to build and run tests - - JDK="${TARGET_JDK}" - - source ~/.install-jdk-travis.sh - - - flutter doctor -v - - # wait for emulator to finish startup - - ./scripts/android-wait-for-emulator.sh - # unlock screen - - adb shell input keyevent 82 & - - script: travis_retry ./scripts/ci.sh ./bloc_flutter - cache: - directories: - - $HOME/.pub-cache - - $HOME/.gradle - -# - <<: *integration-test - - stage: Testing - os: osx -# osx_image: xcode9.4 -# osx_image: xcode9.2 - osx_image: xcode11.3 # for firebase - env: bloc_flutter_ios -# env: vanilla_ios - # Run integration tests on ios - before_install: &before_install_osx -# - xcrun simctl list devicetypes -# - xcrun simctl list runtimes -# # create simulator -# - udid=$(xcrun simctl create "iPhone X" com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-11-2) -# # boot simulator -# - xcrun simctl boot $udid -# - xcrun simctl list - - xcrun simctl create "iPhone X" com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-3 | xargs xcrun simctl boot - # skip homebrew update - - export HOMEBREW_NO_AUTO_UPDATE=1 - # - brew update - - brew install libimobiledevice - - brew install ideviceinstaller - - brew install ios-deploy - - sudo gem install cocoapods - - # install pre-compiled flutter - - wget --quiet --output-document=flutter.zip https://storage.googleapis.com/flutter_infra/releases/${FLUTTER_CHANNEL}/macos/flutter_macos_v${FLUTTER_VERSION}.zip && unzip -qq flutter.zip > /dev/null && rm flutter.zip - - export PATH="$PATH":"$HOME/.pub-cache/bin" - - export PATH=$PWD/flutter/bin:$PWD/flutter/bin/cache/dart-sdk/bin:$PATH - - flutter doctor -v - script: travis_retry ./scripts/ci.sh ./bloc_flutter - cache: - directories: - - $HOME/.pub-cache - - - <<: *integration-test - os: linux - env: built_redux_android - script: travis_retry ./scripts/ci.sh ./built_redux - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: built_redux_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./built_redux - - <<: *integration-test - os: linux - env: bloc_library_android - script: travis_retry ./scripts/ci.sh ./bloc_library - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: bloc_library_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./bloc_library - - <<: *integration-test - os: linux - env: firestore_redux_android - script: travis_retry ./scripts/ci.sh ./firestore_redux - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: firestore_redux_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./firestore_redux - - <<: *integration-test - os: linux - env: frideos_library_android - script: travis_retry ./scripts/ci.sh ./frideos_library - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: frideos_library_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./frideos_library - - <<: *integration-test - os: linux - env: inherited_widget_android - script: travis_retry ./scripts/ci.sh ./inherited_widget - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: inherited_widget_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./inherited_widget - - <<: *integration-test - os: linux - env: mvc_android - script: travis_retry ./scripts/ci.sh ./mvc - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: mvc_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./mvc - - <<: *integration-test - os: linux - env: mvi_flutter_android - script: travis_retry ./scripts/ci.sh ./mvi_flutter - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: mvi_flutter_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./mvi_flutter - - <<: *integration-test - os: linux - env: mvu_android - script: travis_retry ./scripts/ci.sh ./mvu - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: mvu_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./mvu - - <<: *integration-test - os: linux - env: redux_android - script: travis_retry ./scripts/ci.sh ./redux - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: redux_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./redux - - <<: *integration-test - os: linux - env: change_notifier_provider_android - script: travis_retry ./scripts/ci.sh ./change_notifier_provider - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: change_notifier_provider_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./change_notifier_provider - - <<: *integration-test - os: linux - env: scoped_model_android - script: travis_retry ./scripts/ci.sh ./scoped_model - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: scoped_model_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./scoped_model - - <<: *integration-test - os: linux - env: simple_bloc_flutter_android - script: travis_retry ./scripts/ci.sh ./simple_bloc_flutter - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: simple_bloc_flutter_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./simple_bloc_flutter - - <<: *integration-test - os: linux - env: vanilla_android - script: travis_retry ./scripts/ci.sh ./vanilla - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: vanilla_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./vanilla - - <<: *integration-test - os: linux - env: mobx_android - script: travis_retry ./scripts/ci.sh ./mobx - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: mobx_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./mobx - - <<: *integration-test - os: linux - env: states_rebuilder_android - script: travis_retry ./scripts/ci.sh ./states_rebuilder - - <<: *integration-test - os: osx - osx_image: xcode11.3 - env: states_rebuilder_ios - before_install: *before_install_osx - script: travis_retry ./scripts/ci.sh ./states_rebuilder - - allow_failures: -# - env: -# - bloc_flutter_ios -# - built_redux_android -# - firestore_redux_android -# - firestore_redux_ios -# - mvu_android -# - mvu_ios diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 791a857f..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Changelog - -## 0.0.1 - -- Initial version, created by Stagehand diff --git a/Makefile b/Makefile deleted file mode 100644 index 74218fa2..00000000 --- a/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -.PHONY: clean localize all check_env - -FILES := $(shell find . -name '*.arb' | xargs) - -all: localize - -localize: check_env clean - flutter pub pub run intl_translation:extract_to_arb --output-dir=./ --no-transformer lib/src/localization.dart - mv intl_messages.arb intl_en.arb - flutter pub pub run intl_translation:generate_from_arb --no-use-deferred-loading lib/src/localization.dart $(FILES) - mv messages*.dart lib/src/localizations - -clean: - rm -f *.arb - -check_env: -ifndef FLUTTER_ROOT - $(error FLUTTER_ROOT is undefined. Please export a FLUTTER_ROOT pointing to the installation of Flutter.) -endif diff --git a/README.md b/README.md index fe2edd8f..646740c2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ # flutter_architecture_samples -[![Build Status](https://travis-ci.org/brianegan/flutter_architecture_samples.svg?branch=master)](https://travis-ci.org/brianegan/flutter_architecture_samples) -[![Build Status](https://api.cirrus-ci.com/github/brianegan/flutter_architecture_samples.svg)](https://cirrus-ci.com/github/brianegan/flutter_architecture_samples) -[![codecov](https://codecov.io/gh/brianegan/flutter_architecture_samples/branch/master/graph/badge.svg)](https://codecov.io/gh/brianegan/flutter_architecture_samples) +[![Build Status](https://github.com/brianegan/flutter_architecture_samples/actions/workflows/analyze_test_build.yml/badge.svg?branch=main)](https://github.com/brianegan/flutter_architecture_samples/actions/workflows/analyze_test_build.ymll) +[![codecov](https://codecov.io/gh/brianegan/flutter_architecture_samples/branch/main/graph/badge.svg)](https://codecov.io/gh/brianegan/flutter_architecture_samples) List of Todos Screen @@ -18,35 +17,30 @@ The Flutter Architecture Samples project demonstrates strategies to help solve or avoid these common problems. This project implements the same app using different architectural concepts and tools. -You can use the samples in this project as a learning reference, or as a -starting point for creating your own apps. The focus of this project is on -demonstrating how to structure your code, design your architecture, and the -eventual impact of adopting these patterns on testing and maintaining your app. -You can use the techniques demonstrated here in many different ways to build -apps. Your own particular priorities will impact how you implement the concepts -in these projects, so you should not consider these samples to be canonical -examples. To ensure the focus is kept on the aims described above, the app uses -a simple UI. +You can use the samples in this project as a learning reference, as a roughly +apples-to-apples comparison of different approaches, or as a starting point for +creating your own apps. The focus of this project is on demonstrating how to +structure your code, design your architecture, and the eventual impact of +adopting these patterns on testing and maintaining your app. You can use the +techniques demonstrated here in many different ways to build apps. Your own +particular priorities will impact how you implement the concepts in these +projects, so you should not consider these samples to be canonical examples. To +ensure the focus is kept on the aims described above, the app uses a simple UI. ### Current Samples -- [Vanilla Lifting State Up Example](vanilla) ([Web Demo](https://fas_vanilla.codemagic.app)) - Uses the tools Flutter provides out of the box to manage app state. -- [InheritedWidget Example](inherited_widget) ([Web Demo](https://fas_inherited_widget.codemagic.app)) - Uses an InheritedWidget to pass app state down the widget hierarchy. -- [Change Notifier + Provider Example](change_notifier_provider) ([Web Demo](https://fas_change_notifier_provider.codemagic.app)) - Uses the [ChangeNotifier](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html) class from Flutter with [provider](https://pub.dev/packages/provider) package now recommended by the Flutter team. -- [BLoC Example](bloc_flutter) ([Web Demo](https://fas_bloc_flutter.codemagic.app)) - An implementation of the BLoC pattern, which uses Sinks for Inputs and Streams for Outputs -- [Bloc Library Example](bloc_library) ([Web Demo](https://fas_bloc_library.codemagic.app)) - Uses the [bloc](https://pub.dartlang.org/packages/bloc) and [flutter_bloc](https://pub.dartlang.org/packages/flutter_bloc) libraries to manage app state and update Widgets. -- [MobX Example](mobx) ([Web Demo](https://fas_mobx.codemagic.app)) - Uses the [MobX](https://pub.dev/packages/mobx) library to manage app state and update widgets using `Observables`, `Actions` and `Reactions`. -- [Redux Example](redux) ([Web Demo](https://fas_redux.codemagic.app)) - Uses the [Redux](https://pub.dartlang.org/packages/redux) library to manage app state and update Widgets -- ["Simple" BLoC Example](simple_bloc_flutter) ([Web Demo](https://fas_simple_bloc.codemagic.app)) - Similar to the BLoC pattern, but uses Functions for Inputs and Streams for Outputs. Results in far less code compared to standard BLoC. -- [MVI Example](mvi_flutter) ([Web Demo](https://fas_mvi.codemagic.app)) - Uses the concepts from Cycle.JS and applies them to Flutter. -- [states_rebuilder Example](states_rebuilder) ([Web Demo](https://fas_states_rebuilder.codemagic.app)) - Uses the [states_rebuilder](https://pub.dev/packages/states_rebuilder) library to manage app state and update Widgets. -- [built_redux Example](built_redux) - Uses the [built_redux](https://pub.dartlang.org/packages/built_redux) library to enforce immutability and manage app state -- [scoped_model Example](scoped_model) - Uses the [scoped_model](https://pub.dartlang.org/packages/scoped_model) library to hold app state and notify Widgets of Updates -- [Firestore Redux Example](firestore_redux) - Uses the [Redux](https://pub.dartlang.org/packages/redux) library to manage app state and update Widgets and - adds [Cloud_Firestore](https://firebase.google.com/docs/firestore/) as the Todos database. -- [MVU Example](mvu) - Uses the [dartea](https://pub.dartlang.org/packages/dartea) library to manage app state and update Widgets. -- [MVC Example](mvc) - Uses the [MVC](https://pub.dartlang.org/packages/mvc_pattern) library to implement the traditional MVC design pattern. -- [Frideos Example](frideos_library) - Uses the [Frideos](https://pub.dartlang.org/packages/frideos) library to manage app state and update widgets using streams. +- [Vanilla Lifting State Up Example](vanilla) ([Web Demo](https://fas-vanilla.netlify.app)) - Uses the tools Flutter provides out of the box to manage app state. +- [InheritedWidget Example](inherited_widget) ([Web Demo](https://fas-inherited-widget.netlify.app)) - Uses an InheritedWidget to pass app state down the widget hierarchy. +- [Change Notifier + Provider Example](change_notifier_provider) ([Web Demo](https://fas-change-notifier-provider.netlify.app)) - Uses the [ChangeNotifier](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html) class from Flutter with [provider](https://pub.dev/packages/provider) package now recommended by the Flutter team. +- [Freezed + Provider + Value Notifier](freezed_provider_value_notifier) ([Web Demo](https://fas-freezed-provider-value-notifier.netlify.app)) - Uses the [ValueNotifier](https://api.flutter.dev/flutter/foundation/ValueNotifier-class.html) class from Flutter with [provider](https://pub.dev/packages/provider) package. +- [BLoC Example](bloc_flutter) ([Web Demo](https://fas-bloc-flutter.netlify.app/)) - An implementation of the original [BLoC pattern](https://www.youtube.com/watch?v=PLHln7wHgPE&list=PLOU2XLYxmsIIJr3vjxggY7yGcGO7i9BK5&index=13) described by Paolo Soares at DartConf 2018, which uses Sinks for Inputs and Streams for Outputs +- [Bloc Library Example](bloc_library) ([Web Demo](https://fas-bloc-library.netlify.app)) - Uses the [bloc](https://pub.dartlang.org/packages/bloc) and [flutter_bloc](https://pub.dartlang.org/packages/flutter_bloc) libraries to manage app state and update Widgets. +- [MobX Example](mobx) ([Web Demo](https://fas-mobx.netlify.app)) - Uses the [MobX](https://pub.dev/packages/mobx) library to manage app state and update widgets using `Observables`, `Actions` and `Reactions`. +- [Redux Example](redux) ([Web Demo](https://fas-redux.netlify.app)) - Uses the [Redux](https://pub.dartlang.org/packages/redux) library to manage app state and update Widgets +- ["Simple" BLoC Example](simple_bloc_flutter) ([Web Demo](https://fas-simple-bloc.netlify.app/)) - Similar to the BLoC pattern, but uses Functions for Inputs and Streams for Outputs. Results in far less code compared to original BLoC pattern if code sharing with AngularDart apps isn't an important use case for your app. +- [Signals Example](signals) ([Web Demo](https://fas-signals.netlify.app)) - Uses the [Signals](https://pub.dev/packages/signals) package by [Rody Davis](https://pub.dev/publishers/rodydavis.com/packages). +- [MVI Example](mvi_flutter) ([Web Demo](https://fas-mvi.netlify.app)) - Uses the concepts from [Cycle.JS](https://cycle.js.org/) and applies them to Flutter. +- [scoped_model Example](scoped_model) ([Web Demo](https://fas-scoped-model.netlify.app)) - Uses the [scoped_model](https://pub.dartlang.org/packages/scoped_model) library to hold app state and notify Widgets of Updates ### Supporting Code @@ -60,37 +54,19 @@ window.localStorage for web projects. - [todos_repository_local_storage](todos_repository_local_storage) - Implements the todos repository using the file system, window.localStorage, and SharedPreferences as the data source. -- [firebase_flutter_repository](firebase_flutter_repository) - Implements -the todos repository using firestore as the data source. -- [firebase_rtdb_flutter_repository](firebase_rtdb_flutter_repository) - -Implements the todos repository using firebase real-time database as the data -source. ### Running the samples -#### iOS / Android - ``` cd flutter run ``` -#### Web - -Make sure you're on Flutter version "Flutter 1.12.13+hotfix.6 • channel beta" or -newer. Not all samples support web at this time, so please check the sample -directory for a `lib/main_web.dart` file. - -``` -cd -flutter run -d chrome -t lib/main_web.dart -``` - ### Why a todo app? -The app in this project aims to be simple enough that you can understand it -quickly, but complex enough to showcase difficult design decisions and testing -scenarios. For more information, see the [app's specification](app_spec.md). +The app in this project aims to be as simple as possible while still showcasing +different design decisions and testing scenarios. For more information, see the +[app's specification](app_spec.md). ### Be excellent to each other diff --git a/analysis_options.yaml b/analysis_options.yaml deleted file mode 100644 index 962f9342..00000000 --- a/analysis_options.yaml +++ /dev/null @@ -1,56 +0,0 @@ -# Pedantic 1.9.0 -# -# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -# for details. All rights reserved. Use of this source code is governed by a -# BSD-style license that can be found in the LICENSE file. -# -# Google internally enforced rules. See README.md for more information, -# including a list of lints that are intentionally _not_ enforced. - -linter: - rules: - - always_declare_return_types - - always_require_non_null_named_parameters - - annotate_overrides - - avoid_empty_else - - avoid_init_to_null - - avoid_null_checks_in_equality_operators - - avoid_relative_lib_imports - - avoid_return_types_on_setters - - avoid_shadowing_type_parameters - - avoid_types_as_parameter_names - - camel_case_extensions - - curly_braces_in_flow_control_structures - - empty_catches - - empty_constructor_bodies - - library_names - - library_prefixes - - no_duplicate_case_values - - null_closures - - omit_local_variable_types - - prefer_adjacent_string_concatenation - - prefer_collection_literals - - prefer_conditional_assignment - - prefer_contains - - prefer_equal_for_default_values - - prefer_final_fields - - prefer_for_elements_to_map_fromIterable - - prefer_generic_function_type_aliases - - prefer_if_null_operators - - prefer_is_empty - - prefer_is_not_empty - - prefer_iterable_whereType - - prefer_single_quotes - - prefer_spread_collections - - recursive_getters - - slash_for_doc_comments - - type_init_formals - - unawaited_futures - - unnecessary_const - - unnecessary_new - - unnecessary_null_in_if_null_operators - - unnecessary_this - - unrelated_type_equality_checks - - use_function_type_syntax_for_parameters - - use_rethrow_when_possible - - valid_regexps diff --git a/app_spec.md b/app_spec.md index 751da2c2..3351d1cc 100644 --- a/app_spec.md +++ b/app_spec.md @@ -1,6 +1,6 @@ # Application Specification -We have created this short spec to help you create awesome and consistent todo apps. Make sure to not only read it but to understand it as well. +We have created this short spec to help you create consistent todo apps. Consistency is key to form an "apples to apples" comparison between different approaches. ## Reference Application @@ -17,8 +17,9 @@ All examples must include a README describing the general implementation, any fr - Format your code with `dartfmt` - Use the `.analysis_options.yaml` from the vanilla implementation and ensure there are no analysis errors - Use the Theme and Widgets provided by the base package for the visual look, unless it makes sense to demonstrate an alternative practice. -- Your app should work on both Android and iOS +- Your app should work on all platforms - Your app should contain tests +- Your app must pass the integration tests ## User Interface diff --git a/assets/add-todo.png b/assets/add-todo.png index 606fc63f..2b2d365f 100644 Binary files a/assets/add-todo.png and b/assets/add-todo.png differ diff --git a/assets/edit-todo.png b/assets/edit-todo.png index 17579d0a..44851a58 100644 Binary files a/assets/edit-todo.png and b/assets/edit-todo.png differ diff --git a/assets/favicon-16x16.png b/assets/favicon-16x16.png index ee713738..d7013256 100644 Binary files a/assets/favicon-16x16.png and b/assets/favicon-16x16.png differ diff --git a/assets/favicon-32x32.png b/assets/favicon-32x32.png index cad7bfaf..af89dc70 100644 Binary files a/assets/favicon-32x32.png and b/assets/favicon-32x32.png differ diff --git a/assets/filter.png b/assets/filter.png index cca3a364..73eef157 100644 Binary files a/assets/filter.png and b/assets/filter.png differ diff --git a/assets/mark-all.png b/assets/mark-all.png index 4a758e54..15ec9dcc 100644 Binary files a/assets/mark-all.png and b/assets/mark-all.png differ diff --git a/assets/screenshot.png b/assets/screenshot.png index ec0b619a..03390a8d 100644 Binary files a/assets/screenshot.png and b/assets/screenshot.png differ diff --git a/assets/stats.png b/assets/stats.png index d9729597..a1f4e774 100644 Binary files a/assets/stats.png and b/assets/stats.png differ diff --git a/assets/todo-details.png b/assets/todo-details.png index 59fd22ba..f5f8445d 100644 Binary files a/assets/todo-details.png and b/assets/todo-details.png differ diff --git a/assets/todo-list.png b/assets/todo-list.png index 30f8b5b5..68f55686 100644 Binary files a/assets/todo-list.png and b/assets/todo-list.png differ diff --git a/bloc_flutter/.metadata b/bloc_flutter/.metadata index 1b5cec02..05a8ab44 100644 --- a/bloc_flutter/.metadata +++ b/bloc_flutter/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: 27321ebbad34b0a3fafe99fac037102196d655ff - channel: stable + revision: "05db9689081f091050f01aed79f04dce0c750154" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: android + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: ios + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: linux + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: macos + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: web + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: windows + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/bloc_flutter/analysis_options.yaml b/bloc_flutter/analysis_options.yaml new file mode 100644 index 00000000..134f2137 --- /dev/null +++ b/bloc_flutter/analysis_options.yaml @@ -0,0 +1,34 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# 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 +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + # The lint rules applied to this project can be customized in the + # 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 + # and their documentation is published at https://dart.dev/lints. + # + # 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 + # 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 + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/bloc_flutter/android/.gitignore b/bloc_flutter/android/.gitignore index bc2100d8..be3943c9 100644 --- a/bloc_flutter/android/.gitignore +++ b/bloc_flutter/android/.gitignore @@ -5,3 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/bloc_flutter/android/app/build.gradle b/bloc_flutter/android/app/build.gradle deleted file mode 100644 index b0d80781..00000000 --- a/bloc_flutter/android/app/build.gradle +++ /dev/null @@ -1,68 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.bloc_flutter" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - multiDexEnabled true - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/bloc_flutter/android/app/build.gradle.kts b/bloc_flutter/android/app/build.gradle.kts new file mode 100644 index 00000000..f8e5e923 --- /dev/null +++ b/bloc_flutter/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.bloc_flutter_sample" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.bloc_flutter_sample" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/bloc_flutter/android/app/src/debug/AndroidManifest.xml b/bloc_flutter/android/app/src/debug/AndroidManifest.xml index 0e7c814b..399f6981 100644 --- a/bloc_flutter/android/app/src/debug/AndroidManifest.xml +++ b/bloc_flutter/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/bloc_flutter/android/app/src/main/AndroidManifest.xml b/bloc_flutter/android/app/src/main/AndroidManifest.xml index 02fd0f47..9866d0a0 100644 --- a/bloc_flutter/android/app/src/main/AndroidManifest.xml +++ b/bloc_flutter/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,25 @@ - - + + + @@ -27,4 +31,15 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + diff --git a/bloc_flutter/android/app/src/main/kotlin/com/example/bloc_flutter/MainActivity.kt b/bloc_flutter/android/app/src/main/kotlin/com/example/bloc_flutter/MainActivity.kt deleted file mode 100644 index 4a5aea1c..00000000 --- a/bloc_flutter/android/app/src/main/kotlin/com/example/bloc_flutter/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.bloc_flutter - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/bloc_flutter/android/app/src/main/kotlin/com/example/bloc_flutter_sample/MainActivity.kt b/bloc_flutter/android/app/src/main/kotlin/com/example/bloc_flutter_sample/MainActivity.kt new file mode 100644 index 00000000..c525aee6 --- /dev/null +++ b/bloc_flutter/android/app/src/main/kotlin/com/example/bloc_flutter_sample/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.bloc_flutter_sample + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/bloc_flutter/android/app/src/main/res/drawable-v21/launch_background.xml b/bloc_flutter/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/bloc_flutter/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/bloc_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/bloc_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index a3f285f9..db77bb4b 100644 Binary files a/bloc_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/bloc_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/bloc_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/bloc_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 5e6f3ac6..17987b79 100644 Binary files a/bloc_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/bloc_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/bloc_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/bloc_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 144d60be..09d43914 100644 Binary files a/bloc_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/bloc_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/bloc_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/bloc_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index deafae2d..d5f1c8d3 100644 Binary files a/bloc_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/bloc_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/bloc_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/bloc_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index d5614ac8..4d6372ee 100644 Binary files a/bloc_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/bloc_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/bloc_flutter/android/app/src/main/res/values-night/styles.xml b/bloc_flutter/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/bloc_flutter/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/bloc_flutter/android/app/src/main/res/values/styles.xml b/bloc_flutter/android/app/src/main/res/values/styles.xml index 00fa4417..cb1ef880 100644 --- a/bloc_flutter/android/app/src/main/res/values/styles.xml +++ b/bloc_flutter/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ - + + diff --git a/bloc_flutter/android/app/src/profile/AndroidManifest.xml b/bloc_flutter/android/app/src/profile/AndroidManifest.xml index 0e7c814b..399f6981 100644 --- a/bloc_flutter/android/app/src/profile/AndroidManifest.xml +++ b/bloc_flutter/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/bloc_flutter/android/build.gradle b/bloc_flutter/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/bloc_flutter/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/bloc_flutter/android/build.gradle.kts b/bloc_flutter/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/bloc_flutter/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/bloc_flutter/android/gradle.properties b/bloc_flutter/android/gradle.properties index 38c8d454..f018a618 100644 --- a/bloc_flutter/android/gradle.properties +++ b/bloc_flutter/android/gradle.properties @@ -1,4 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/bloc_flutter/android/gradle/wrapper/gradle-wrapper.properties b/bloc_flutter/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..ac3b4792 100644 --- a/bloc_flutter/android/gradle/wrapper/gradle-wrapper.properties +++ b/bloc_flutter/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/bloc_flutter/android/settings.gradle b/bloc_flutter/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/bloc_flutter/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/bloc_flutter/android/settings.gradle.kts b/bloc_flutter/android/settings.gradle.kts new file mode 100644 index 00000000..fb605bc8 --- /dev/null +++ b/bloc_flutter/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/bloc_flutter/integration_test/app_test.dart b/bloc_flutter/integration_test/app_test.dart new file mode 100644 index 00000000..26407e76 --- /dev/null +++ b/bloc_flutter/integration_test/app_test.dart @@ -0,0 +1,26 @@ +import 'package:bloc_flutter_sample/anonymous_user_repository.dart'; +import 'package:bloc_flutter_sample/app.dart'; +import 'package:blocs/blocs.dart'; +import 'package:integration_tests/integration_tests.dart' as integration_tests; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; + +void main() { + integration_tests.run( + appBuilder: () async { + return BlocApp( + todosInteractor: TodosInteractor( + ReactiveLocalStorageRepository( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'bloc_flutter_test_${DateTime.now().toIso8601String()}', + await SharedPreferences.getInstance(), + ), + ), + ), + ), + userRepository: AnonymousUserRepository(), + ); + }, + ); +} diff --git a/bloc_flutter/ios/.gitignore b/bloc_flutter/ios/.gitignore index e96ef602..7a7f9873 100644 --- a/bloc_flutter/ios/.gitignore +++ b/bloc_flutter/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/bloc_flutter/ios/Flutter/AppFrameworkInfo.plist b/bloc_flutter/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f78..1dc6cf76 100644 --- a/bloc_flutter/ios/Flutter/AppFrameworkInfo.plist +++ b/bloc_flutter/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 13.0 diff --git a/bloc_flutter/ios/Flutter/Debug.xcconfig b/bloc_flutter/ios/Flutter/Debug.xcconfig index e8efba11..ec97fc6f 100644 --- a/bloc_flutter/ios/Flutter/Debug.xcconfig +++ b/bloc_flutter/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/bloc_flutter/ios/Flutter/Release.xcconfig b/bloc_flutter/ios/Flutter/Release.xcconfig index 399e9340..c4855bfe 100644 --- a/bloc_flutter/ios/Flutter/Release.xcconfig +++ b/bloc_flutter/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/bloc_flutter/ios/Podfile b/bloc_flutter/ios/Podfile index b30a428b..620e46eb 100644 --- a/bloc_flutter/ios/Podfile +++ b/bloc_flutter/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -10,81 +10,34 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - generated_key_values + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' +flutter_ios_podfile_setup - # Plugin Pods +target 'Runner' do + use_frameworks! - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths end end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/bloc_flutter/ios/Runner.xcodeproj/project.pbxproj b/bloc_flutter/ios/Runner.xcodeproj/project.pbxproj index a861f735..92c13a07 100644 --- a/bloc_flutter/ios/Runner.xcodeproj/project.pbxproj +++ b/bloc_flutter/ios/Runner.xcodeproj/project.pbxproj @@ -3,24 +3,29 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 2366E5FF7225C36570C36ADF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B18CA89E2996A6B263F66545 /* Pods_Runner.framework */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 4EEE3E8F23C4927D0065A5A2 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4EEE3E8E23C4927D0065A5A2 /* GoogleService-Info.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -28,8 +33,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -39,24 +42,19 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3219E38D9738F4AC7121FB7B /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 4EEE3E8E23C4927D0065A5A2 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - B18CA89E2996A6B263F66545 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - DD8741825F163AC04489B25F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - EB174B8697ECB290E7346D6E /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -64,40 +62,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - 2366E5FF7225C36570C36ADF /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 4DEAD570AC93508D92C128F4 /* Pods */ = { - isa = PBXGroup; - children = ( - EB174B8697ECB290E7346D6E /* Pods-Runner.debug.xcconfig */, - 3219E38D9738F4AC7121FB7B /* Pods-Runner.release.xcconfig */, - DD8741825F163AC04489B25F /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - 65314717153277BBBD59EF57 /* Frameworks */ = { + 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( - B18CA89E2996A6B263F66545 /* Pods_Runner.framework */, + 331C807B294A618700263BE5 /* RunnerTests.swift */, ); - name = Frameworks; + path = RunnerTests; sourceTree = ""; }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -108,12 +90,10 @@ 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( - 4EEE3E8E23C4927D0065A5A2 /* GoogleService-Info.plist */, 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - 4DEAD570AC93508D92C128F4 /* Pods */, - 65314717153277BBBD59EF57 /* Frameworks */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -121,6 +101,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -132,7 +113,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -141,28 +121,36 @@ path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - B4149F1FCA3B6359C6408BDA /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 7D98778AC99E43569AB862F5 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -179,9 +167,14 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -189,7 +182,7 @@ }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -202,18 +195,25 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 4EEE3E8F23C4927D0065A5A2 /* GoogleService-Info.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); @@ -224,35 +224,23 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 7D98778AC99E43569AB862F5 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -265,31 +253,17 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - B4149F1FCA3B6359C6408BDA /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -301,6 +275,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -323,9 +305,9 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -355,6 +337,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -363,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -379,18 +362,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutter; + PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutterSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -398,11 +377,58 @@ }; name = Profile; }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -432,6 +458,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -446,7 +473,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -456,9 +483,9 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -488,6 +515,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -496,11 +524,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -513,18 +542,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutter; + PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutterSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -540,18 +565,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutter; + PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutterSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -562,6 +583,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/bloc_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/bloc_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..e3773d42 100644 --- a/bloc_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/bloc_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + + + + + @@ -61,8 +73,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - - - diff --git a/bloc_flutter/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/bloc_flutter/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/bloc_flutter/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/bloc_flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/bloc_flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/bloc_flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/bloc_flutter/ios/Runner/AppDelegate.swift b/bloc_flutter/ios/Runner/AppDelegate.swift index 70693e4a..62666446 100644 --- a/bloc_flutter/ios/Runner/AppDelegate.swift +++ b/bloc_flutter/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ -import UIKit import Flutter +import UIKit -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d22f10b2..d36b1fab 100644 --- a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -107,6 +107,12 @@ "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" } ], "info" : { diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png similarity index 100% rename from states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png rename to bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 980e5ad6..7353c41e 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index fd870289..797d452e 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 75e84cd1..6ed2d933 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 03ab8a84..4cd7b009 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index a03431cb..fe730945 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index f47613ee..321773cd 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 7f2230a9..797d452e 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 42315c6d..502f463a 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index f9882cc0..0ec30343 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 45537513..0ec30343 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 6360ea17..e9f5fea2 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 152d5e12..84ac32ae 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 310b0b8f..8953cba0 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 092b7bfe..0467bf12 100644 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/bloc_flutter/ios/Runner/GoogleService-Info.plist b/bloc_flutter/ios/Runner/GoogleService-Info.plist deleted file mode 100644 index c8cc9bf9..00000000 --- a/bloc_flutter/ios/Runner/GoogleService-Info.plist +++ /dev/null @@ -1,40 +0,0 @@ - - - - - AD_UNIT_ID_FOR_BANNER_TEST - ca-app-pub-9999999999999999/9999999999 - AD_UNIT_ID_FOR_INTERSTITIAL_TEST - ca-app-pub-9999999999999999/9999999999 - CLIENT_ID - xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com - REVERSED_CLIENT_ID - com.googleusercontent.apps.xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - API_KEY - xxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx - GCM_SENDER_ID - 999999999999 - PLIST_VERSION - 1 - BUNDLE_ID - com.fluttersamples.bloc - PROJECT_ID - xxxxxxxxxxxxx-99999 - STORAGE_BUCKET - xxxxxxxxxxxxx-99999.appspot.com - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 9:999999999999:ios:xxxxxxxxxxxxxxxx - DATABASE_URL - https://xxxxxxxxxxxxx-99999.firebaseio.com - - \ No newline at end of file diff --git a/bloc_flutter/ios/Runner/Info.plist b/bloc_flutter/ios/Runner/Info.plist index dfc13dd4..b34b0a4a 100644 --- a/bloc_flutter/ios/Runner/Info.plist +++ b/bloc_flutter/ios/Runner/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Bloc Flutter Sample CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -11,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - bloc_flutter + bloc_flutter_sample CFBundlePackageType APPL CFBundleShortVersionString @@ -39,7 +41,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/bloc_flutter/ios/Runner/Runner-Bridging-Header.h b/bloc_flutter/ios/Runner/Runner-Bridging-Header.h index 7335fdf9..308a2a56 100644 --- a/bloc_flutter/ios/Runner/Runner-Bridging-Header.h +++ b/bloc_flutter/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file +#import "GeneratedPluginRegistrant.h" diff --git a/bloc_flutter/ios/RunnerTests/RunnerTests.swift b/bloc_flutter/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/bloc_flutter/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/bloc_flutter/lib/anonymous_user_repository.dart b/bloc_flutter/lib/anonymous_user_repository.dart new file mode 100644 index 00000000..efd978f5 --- /dev/null +++ b/bloc_flutter/lib/anonymous_user_repository.dart @@ -0,0 +1,7 @@ +import 'package:todos_repository_core/todos_repository_core.dart'; + +class AnonymousUserRepository implements UserRepository { + @override + Future login() async => + UserEntity(id: 'anonymous', displayName: '', photoUrl: ''); +} diff --git a/bloc_flutter/lib/app.dart b/bloc_flutter/lib/app.dart index 44f322e9..fc998dc8 100644 --- a/bloc_flutter/lib/app.dart +++ b/bloc_flutter/lib/app.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:bloc_flutter_sample/dependency_injection.dart'; import 'package:bloc_flutter_sample/localization.dart'; import 'package:bloc_flutter_sample/screens/add_edit_screen.dart'; @@ -9,7 +5,6 @@ import 'package:bloc_flutter_sample/screens/home_screen.dart'; import 'package:bloc_flutter_sample/widgets/todos_bloc_provider.dart'; import 'package:blocs/blocs.dart'; import 'package:flutter/material.dart'; -import 'package:meta/meta.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -18,10 +13,10 @@ class BlocApp extends StatelessWidget { final UserRepository userRepository; const BlocApp({ - Key key, - @required this.todosInteractor, - @required this.userRepository, - }) : super(key: key); + super.key, + required this.todosInteractor, + required this.userRepository, + }); @override Widget build(BuildContext context) { @@ -32,15 +27,16 @@ class BlocApp extends StatelessWidget { bloc: TodosListBloc(todosInteractor), child: MaterialApp( onGenerateTitle: (context) => BlocLocalizations.of(context).appTitle, - theme: ArchSampleTheme.theme, + theme: ArchSampleTheme.lightTheme, + darkTheme: ArchSampleTheme.darkTheme, localizationsDelegates: [ ArchSampleLocalizationsDelegate(), - InheritedWidgetLocalizationsDelegate(), + BlocLocalizationsDelegate(), ], routes: { ArchSampleRoutes.home: (context) { return HomeScreen( - repository: Injector.of(context).userRepository, + userRepository: Injector.of(context).userRepository, ); }, ArchSampleRoutes.addTodo: (context) { diff --git a/bloc_flutter/lib/dependency_injection.dart b/bloc_flutter/lib/dependency_injection.dart index 2bfdc6b1..0dfc12a7 100644 --- a/bloc_flutter/lib/dependency_injection.dart +++ b/bloc_flutter/lib/dependency_injection.dart @@ -1,29 +1,20 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// A poor man's DI. This should be replaced by a proper solution once they -// are more stable. -library dependency_injector; - import 'package:blocs/blocs.dart'; import 'package:flutter/widgets.dart'; -import 'package:meta/meta.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; class Injector extends InheritedWidget { final TodosInteractor todosInteractor; final UserRepository userRepository; - Injector({ - Key key, - @required this.todosInteractor, - @required this.userRepository, - @required Widget child, - }) : super(key: key, child: child); + const Injector({ + super.key, + required this.todosInteractor, + required this.userRepository, + required super.child, + }); static Injector of(BuildContext context) => - context.dependOnInheritedWidgetOfExactType(); + context.dependOnInheritedWidgetOfExactType()!; @override bool updateShouldNotify(Injector oldWidget) => diff --git a/bloc_flutter/lib/localization.dart b/bloc_flutter/lib/localization.dart index 78698325..bf8ca9c2 100644 --- a/bloc_flutter/lib/localization.dart +++ b/bloc_flutter/lib/localization.dart @@ -1,27 +1,23 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; class BlocLocalizations { static BlocLocalizations of(BuildContext context) { - return Localizations.of(context, BlocLocalizations); + return Localizations.of(context, BlocLocalizations)!; } String get appTitle => 'Bloc Example'; } -class InheritedWidgetLocalizationsDelegate +class BlocLocalizationsDelegate extends LocalizationsDelegate { @override Future load(Locale locale) => Future(() => BlocLocalizations()); @override - bool shouldReload(InheritedWidgetLocalizationsDelegate old) => false; + bool shouldReload(BlocLocalizationsDelegate old) => false; @override bool isSupported(Locale locale) => diff --git a/bloc_flutter/lib/main.dart b/bloc_flutter/lib/main.dart index 29c83666..5d4d3729 100644 --- a/bloc_flutter/lib/main.dart +++ b/bloc_flutter/lib/main.dart @@ -1,38 +1,28 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; +import 'package:bloc_flutter_sample/anonymous_user_repository.dart'; import 'package:bloc_flutter_sample/app.dart'; import 'package:blocs/blocs.dart'; import 'package:flutter/widgets.dart'; -import 'package:key_value_store_flutter/key_value_store_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(BlocApp( - todosInteractor: TodosInteractor( - ReactiveLocalStorageRepository( - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'bloc_todos', - FlutterKeyValueStore(await SharedPreferences.getInstance()), + runApp( + BlocApp( + todosInteractor: TodosInteractor( + ReactiveLocalStorageRepository( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'bloc_todos', + await SharedPreferences.getInstance(), + ), ), ), ), + userRepository: AnonymousUserRepository(), ), - userRepository: AnonymousUserRepository(), - )); -} - -class AnonymousUserRepository implements UserRepository { - @override - Future login() { - return Future.value(UserEntity(id: 'anonymous')); - } + ); } diff --git a/bloc_flutter/lib/main_firebase.dart b/bloc_flutter/lib/main_firebase.dart deleted file mode 100644 index a78bef69..00000000 --- a/bloc_flutter/lib/main_firebase.dart +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:bloc_flutter_sample/app.dart'; -import 'package:blocs/blocs.dart'; -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:firebase_flutter_repository/reactive_todos_repository.dart'; -import 'package:firebase_flutter_repository/user_repository.dart'; -import 'package:flutter/widgets.dart'; - -void main() { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(BlocApp( - todosInteractor: TodosInteractor( - FirestoreReactiveTodosRepository(Firestore.instance), - ), - userRepository: FirebaseUserRepository(FirebaseAuth.instance), - )); -} diff --git a/bloc_flutter/lib/main_web.dart b/bloc_flutter/lib/main_web.dart deleted file mode 100644 index fb868ff1..00000000 --- a/bloc_flutter/lib/main_web.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; -import 'dart:html'; - -import 'package:bloc_flutter_sample/app.dart'; -import 'package:blocs/blocs.dart'; -import 'package:flutter/widgets.dart'; -import 'package:key_value_store_web/key_value_store_web.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(BlocApp( - todosInteractor: TodosInteractor( - ReactiveLocalStorageRepository( - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'bloc_todos', - WebKeyValueStore(window.localStorage), - ), - ), - ), - ), - userRepository: AnonymousUserRepository(), - )); -} - -class AnonymousUserRepository implements UserRepository { - @override - Future login() { - return Future.value(UserEntity(id: 'anonymous')); - } -} diff --git a/bloc_flutter/lib/screens/add_edit_screen.dart b/bloc_flutter/lib/screens/add_edit_screen.dart index 611399e4..6bbe35b1 100644 --- a/bloc_flutter/lib/screens/add_edit_screen.dart +++ b/bloc_flutter/lib/screens/add_edit_screen.dart @@ -1,37 +1,33 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - import 'package:blocs/blocs.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; class AddEditScreen extends StatefulWidget { - final Todo todo; - final Function(Todo) addTodo; - final Function(Todo) updateTodo; + final Todo? todo; + final void Function(Todo)? addTodo; + final void Function(Todo)? updateTodo; - AddEditScreen({ - Key key, + const AddEditScreen({ + super.key = ArchSampleKeys.addTodoScreen, this.todo, this.addTodo, this.updateTodo, - }) : super(key: key ?? ArchSampleKeys.addTodoScreen); + }); @override - _AddEditScreenState createState() => _AddEditScreenState(); + AddEditScreenState createState() => AddEditScreenState(); } -class _AddEditScreenState extends State { +class AddEditScreenState extends State { static final GlobalKey formKey = GlobalKey(); - String _task; - String _note; + late String _task; + late String _note; @override Widget build(BuildContext context) { + final isEditing = widget.todo != null; + return Scaffold( appBar: AppBar( title: Text( @@ -44,58 +40,56 @@ class _AddEditScreenState extends State { padding: EdgeInsets.all(16.0), child: Form( key: formKey, - autovalidate: false, - onWillPop: () { - return Future(() => true); - }, + autovalidateMode: AutovalidateMode.always, + canPop: true, child: ListView( children: [ TextFormField( - initialValue: widget.todo != null ? widget.todo.task : '', + initialValue: isEditing ? widget.todo!.task : '', key: ArchSampleKeys.taskField, autofocus: isEditing ? false : true, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, decoration: InputDecoration( hintText: ArchSampleLocalizations.of(context).newTodoHint, ), - validator: (val) => val.trim().isEmpty + validator: (val) => val != null && val.trim().isEmpty ? ArchSampleLocalizations.of(context).emptyTodoError : null, - onSaved: (value) => _task = value, + onSaved: (value) => _task = value ?? '', ), TextFormField( - initialValue: widget.todo != null ? widget.todo.note : '', + initialValue: isEditing ? widget.todo!.note : '', key: ArchSampleKeys.noteField, maxLines: 10, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, decoration: InputDecoration( hintText: ArchSampleLocalizations.of(context).notesHint, ), - onSaved: (value) => _note = value, - ) + onSaved: (value) => _note = value ?? '', + ), ], ), ), ), floatingActionButton: FloatingActionButton( - key: - isEditing ? ArchSampleKeys.saveTodoFab : ArchSampleKeys.saveNewTodo, + key: isEditing + ? ArchSampleKeys.saveTodoFab + : ArchSampleKeys.saveNewTodo, tooltip: isEditing ? ArchSampleLocalizations.of(context).saveChanges : ArchSampleLocalizations.of(context).addTodo, child: Icon(isEditing ? Icons.check : Icons.add), onPressed: () { final form = formKey.currentState; - if (form.validate()) { + if (form!.validate()) { form.save(); if (isEditing) { - widget.updateTodo(widget.todo.copyWith(task: _task, note: _note)); + widget.updateTodo!( + widget.todo!.copyWith(task: _task, note: _note), + ); } else { - widget.addTodo(Todo( - _task, - note: _note, - )); + widget.addTodo!(Todo(_task, note: _note)); } Navigator.pop(context); @@ -104,6 +98,4 @@ class _AddEditScreenState extends State { ), ); } - - bool get isEditing => widget.todo != null; } diff --git a/bloc_flutter/lib/screens/detail_screen.dart b/bloc_flutter/lib/screens/detail_screen.dart index d11cd801..b410c129 100644 --- a/bloc_flutter/lib/screens/detail_screen.dart +++ b/bloc_flutter/lib/screens/detail_screen.dart @@ -1,11 +1,6 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:bloc_flutter_sample/screens/add_edit_screen.dart'; import 'package:bloc_flutter_sample/widgets/loading.dart'; import 'package:blocs/blocs.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; @@ -13,10 +8,11 @@ class DetailScreen extends StatefulWidget { final String todoId; final TodoBloc Function() initBloc; - DetailScreen({ - @required this.todoId, - @required this.initBloc, - }) : super(key: ArchSampleKeys.todoDetailsScreen); + const DetailScreen({ + super.key = ArchSampleKeys.todoDetailsScreen, + required this.todoId, + required this.initBloc, + }); @override DetailScreenState createState() { @@ -25,7 +21,7 @@ class DetailScreen extends StatefulWidget { } class DetailScreenState extends State { - TodoBloc todoBloc; + late TodoBloc todoBloc; @override void initState() { @@ -42,11 +38,11 @@ class DetailScreenState extends State { @override Widget build(BuildContext context) { return StreamBuilder( - stream: todoBloc.todo(widget.todoId).where((todo) => todo != null), + stream: todoBloc.todo(widget.todoId), builder: (context, snapshot) { if (!snapshot.hasData) return LoadingSpinner(); - final todo = snapshot.data; + final todo = snapshot.data!; return Scaffold( appBar: AppBar( @@ -60,7 +56,7 @@ class DetailScreenState extends State { todoBloc.deleteTodo.add(todo.id); Navigator.pop(context, todo); }, - ) + ), ], ), body: Padding( @@ -76,8 +72,9 @@ class DetailScreenState extends State { value: todo.complete, key: ArchSampleKeys.detailsTodoItemCheckbox, onChanged: (complete) { - todoBloc.updateTodo - .add(todo.copyWith(complete: !todo.complete)); + todoBloc.updateTodo.add( + todo.copyWith(complete: !todo.complete), + ); }, ), ), @@ -86,21 +83,18 @@ class DetailScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), + padding: EdgeInsets.only(top: 8.0, bottom: 16.0), child: Text( todo.task, key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, ), ), Text( todo.note, key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) + style: Theme.of(context).textTheme.titleMedium, + ), ], ), ), @@ -111,11 +105,10 @@ class DetailScreenState extends State { ), floatingActionButton: FloatingActionButton( tooltip: ArchSampleLocalizations.of(context).editTodo, - child: Icon(Icons.edit), key: ArchSampleKeys.editTodoFab, onPressed: () { Navigator.of(context).push( - MaterialPageRoute( + MaterialPageRoute( builder: (context) { return AddEditScreen( todo: todo, @@ -126,6 +119,7 @@ class DetailScreenState extends State { ), ); }, + child: Icon(Icons.edit), ), ); }, diff --git a/bloc_flutter/lib/screens/home_screen.dart b/bloc_flutter/lib/screens/home_screen.dart index 9429c3a9..f50e1e19 100644 --- a/bloc_flutter/lib/screens/home_screen.dart +++ b/bloc_flutter/lib/screens/home_screen.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:bloc_flutter_sample/dependency_injection.dart'; @@ -14,18 +10,19 @@ import 'package:bloc_flutter_sample/widgets/todo_list.dart'; import 'package:bloc_flutter_sample/widgets/todos_bloc_provider.dart'; import 'package:blocs/blocs.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:meta/meta.dart'; import 'package:rxdart/rxdart.dart'; +import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; enum AppTab { todos, stats } class HomeScreen extends StatefulWidget { - final UserRepository repository; + final UserRepository userRepository; - HomeScreen({@required this.repository}) - : super(key: ArchSampleKeys.homeScreen); + const HomeScreen({ + super.key = ArchSampleKeys.homeScreen, + required this.userRepository, + }); @override State createState() { @@ -34,14 +31,14 @@ class HomeScreen extends StatefulWidget { } class HomeScreenState extends State { - UserBloc usersBloc; - StreamController tabController; + late UserBloc usersBloc; + late StreamController tabController; @override void initState() { super.initState(); - usersBloc = UserBloc(widget.repository); + usersBloc = UserBloc(widget.userRepository); tabController = StreamController(); } @@ -73,25 +70,23 @@ class HomeScreenState extends State { ), body: userSnapshot.hasData ? activeTabSnapshot.data == AppTab.todos - ? TodoList() - : StatsCounter( - buildBloc: () => - StatsBloc(Injector.of(context).todosInteractor), - ) - : LoadingSpinner( - key: ArchSampleKeys.todosLoading, - ), + ? TodoList() + : StatsCounter( + buildBloc: () => + StatsBloc(Injector.of(context).todosInteractor), + ) + : LoadingSpinner(key: ArchSampleKeys.todosLoading), floatingActionButton: FloatingActionButton( key: ArchSampleKeys.addTodoFab, onPressed: () { Navigator.pushNamed(context, ArchSampleRoutes.addTodo); }, - child: Icon(Icons.add), tooltip: ArchSampleLocalizations.of(context).addTodo, + child: Icon(Icons.add), ), bottomNavigationBar: BottomNavigationBar( key: ArchSampleKeys.tabs, - currentIndex: AppTab.values.indexOf(activeTabSnapshot.data), + currentIndex: AppTab.values.indexOf(activeTabSnapshot.data!), onTap: (index) { tabController.add(AppTab.values[index]); }, @@ -103,11 +98,9 @@ class HomeScreenState extends State { ? ArchSampleKeys.statsTab : ArchSampleKeys.todoTab, ), - title: Text( - tab == AppTab.stats - ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos, - ), + label: tab == AppTab.stats + ? ArchSampleLocalizations.of(context).stats + : ArchSampleLocalizations.of(context).todos, ); }).toList(), ), @@ -141,10 +134,7 @@ class HomeScreenState extends State { todosBloc.allComplete, todosBloc.hasCompletedTodos, (allComplete, hasCompletedTodos) { - return ExtraActionsButtonViewModel( - allComplete, - hasCompletedTodos, - ); + return ExtraActionsButtonViewModel(allComplete, hasCompletedTodos); }, ), builder: (context, snapshot) { @@ -160,7 +150,7 @@ class HomeScreenState extends State { }, ); }, - ) + ), ]; } } diff --git a/bloc_flutter/lib/widgets/extra_actions_button.dart b/bloc_flutter/lib/widgets/extra_actions_button.dart index 1f6955b7..809249e8 100644 --- a/bloc_flutter/lib/widgets/extra_actions_button.dart +++ b/bloc_flutter/lib/widgets/extra_actions_button.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; @@ -10,17 +6,16 @@ class ExtraActionsButton extends StatelessWidget { final bool allComplete; final bool hasCompletedTodos; - ExtraActionsButton({ - this.onSelected, + const ExtraActionsButton({ + super.key = ArchSampleKeys.extraActionsButton, + required this.onSelected, this.allComplete = false, this.hasCompletedTodos = true, - Key key, - }) : super(key: key); + }); @override Widget build(BuildContext context) { return PopupMenuButton( - key: ArchSampleKeys.extraActionsButton, onSelected: onSelected, itemBuilder: (BuildContext context) { return >[ @@ -36,9 +31,7 @@ class ExtraActionsButton extends StatelessWidget { PopupMenuItem( key: ArchSampleKeys.clearCompleted, value: ExtraAction.clearCompleted, - child: Text( - ArchSampleLocalizations.of(context).clearCompleted, - ), + child: Text(ArchSampleLocalizations.of(context).clearCompleted), ), ]; }, diff --git a/bloc_flutter/lib/widgets/filter_button.dart b/bloc_flutter/lib/widgets/filter_button.dart index e88a4e43..26a79e98 100644 --- a/bloc_flutter/lib/widgets/filter_button.dart +++ b/bloc_flutter/lib/widgets/filter_button.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:blocs/blocs.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; @@ -11,15 +7,18 @@ class FilterButton extends StatelessWidget { final VisibilityFilter activeFilter; final bool isActive; - FilterButton({this.onSelected, this.activeFilter, this.isActive, Key key}) - : super(key: key); + const FilterButton({ + super.key = ArchSampleKeys.filterButton, + required this.onSelected, + required this.activeFilter, + required this.isActive, + }); @override Widget build(BuildContext context) { - final theme = Theme.of(context); - final defaultStyle = theme.textTheme.body1; - final activeStyle = theme.textTheme.body1.copyWith( - color: theme.accentColor, + final defaultStyle = Theme.of(context).textTheme.bodyMedium!; + final activeStyle = defaultStyle.copyWith( + color: Theme.of(context).colorScheme.secondary, ); final button = _Button( onSelected: onSelected, @@ -38,12 +37,11 @@ class FilterButton extends StatelessWidget { class _Button extends StatelessWidget { const _Button({ - Key key, - @required this.onSelected, - @required this.activeFilter, - @required this.activeStyle, - @required this.defaultStyle, - }) : super(key: key); + required this.onSelected, + required this.activeFilter, + required this.activeStyle, + required this.defaultStyle, + }); final PopupMenuItemSelected onSelected; final VisibilityFilter activeFilter; @@ -53,7 +51,6 @@ class _Button extends StatelessWidget { @override Widget build(BuildContext context) { return PopupMenuButton( - key: ArchSampleKeys.filterButton, tooltip: ArchSampleLocalizations.of(context).filterTodos, onSelected: onSelected, itemBuilder: (BuildContext context) { diff --git a/bloc_flutter/lib/widgets/loading.dart b/bloc_flutter/lib/widgets/loading.dart index 0fa4416a..68c0ec55 100644 --- a/bloc_flutter/lib/widgets/loading.dart +++ b/bloc_flutter/lib/widgets/loading.dart @@ -1,16 +1,10 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; class LoadingSpinner extends StatelessWidget { - LoadingSpinner({Key key}) : super(key: key); + const LoadingSpinner({super.key}); @override Widget build(BuildContext context) { - return Center( - child: CircularProgressIndicator(), - ); + return Center(child: CircularProgressIndicator()); } } diff --git a/bloc_flutter/lib/widgets/stats_counter.dart b/bloc_flutter/lib/widgets/stats_counter.dart index 8780d73a..94467c42 100644 --- a/bloc_flutter/lib/widgets/stats_counter.dart +++ b/bloc_flutter/lib/widgets/stats_counter.dart @@ -1,18 +1,14 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:blocs/blocs.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; class StatsCounter extends StatefulWidget { final StatsBloc Function() buildBloc; - StatsCounter({Key key, @required this.buildBloc}) - : super(key: key ?? ArchSampleKeys.statsCounter); + const StatsCounter({ + super.key = ArchSampleKeys.statsCounter, + required this.buildBloc, + }); @override StatsCounterState createState() { @@ -21,7 +17,7 @@ class StatsCounter extends StatefulWidget { } class StatsCounterState extends State { - StatsBloc bloc; + late StatsBloc bloc; @override void initState() { @@ -39,7 +35,7 @@ class StatsCounterState extends State { padding: EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -49,7 +45,7 @@ class StatsCounterState extends State { builder: (context, snapshot) => Text( '${snapshot.data ?? 0}', key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ), @@ -57,7 +53,7 @@ class StatsCounterState extends State { padding: EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -68,11 +64,11 @@ class StatsCounterState extends State { return Text( '${snapshot.data ?? 0}', key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ); }, ), - ) + ), ], ), ); diff --git a/bloc_flutter/lib/widgets/todo_item.dart b/bloc_flutter/lib/widgets/todo_item.dart index 716f87a5..69250885 100644 --- a/bloc_flutter/lib/widgets/todo_item.dart +++ b/bloc_flutter/lib/widgets/todo_item.dart @@ -1,23 +1,19 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:blocs/blocs.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; class TodoItem extends StatelessWidget { final DismissDirectionCallback onDismissed; final GestureTapCallback onTap; - final ValueChanged onCheckboxChanged; + final ValueChanged onCheckboxChanged; final Todo todo; - TodoItem({ - @required this.onDismissed, - @required this.onTap, - @required this.onCheckboxChanged, - @required this.todo, + const TodoItem({ + super.key, + required this.onDismissed, + required this.onTap, + required this.onCheckboxChanged, + required this.todo, }); @override @@ -35,14 +31,14 @@ class TodoItem extends StatelessWidget { title: Text( todo.task, key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), subtitle: Text( todo.note, key: ArchSampleKeys.todoItemNote(todo.id), maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ); diff --git a/bloc_flutter/lib/widgets/todo_list.dart b/bloc_flutter/lib/widgets/todo_list.dart index e4f24023..77e94689 100644 --- a/bloc_flutter/lib/widgets/todo_list.dart +++ b/bloc_flutter/lib/widgets/todo_list.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:bloc_flutter_sample/dependency_injection.dart'; import 'package:bloc_flutter_sample/screens/detail_screen.dart'; import 'package:bloc_flutter_sample/widgets/loading.dart'; @@ -12,14 +8,14 @@ import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; class TodoList extends StatelessWidget { - TodoList({Key key}) : super(key: key); + const TodoList({super.key}); @override Widget build(BuildContext context) { return StreamBuilder>( stream: TodosBlocProvider.of(context).visibleTodos, builder: (context, snapshot) => snapshot.hasData - ? _buildList(snapshot.data) + ? _buildList(snapshot.data!) : LoadingSpinner(key: ArchSampleKeys.todosLoading), ); } @@ -37,26 +33,28 @@ class TodoList extends StatelessWidget { _removeTodo(context, todo); }, onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) { - return DetailScreen( - todoId: todo.id, - initBloc: () => - TodoBloc(Injector.of(context).todosInteractor), - ); - }, - ), - ).then((todo) { - if (todo is Todo) { - _showUndoSnackbar(context, todo); - } - }); + Navigator.of(context) + .push( + MaterialPageRoute( + builder: (_) { + return DetailScreen( + todoId: todo.id, + initBloc: () => + TodoBloc(Injector.of(context).todosInteractor), + ); + }, + ), + ) + .then((todo) { + if (todo is Todo && context.mounted) { + _showUndoSnackbar(context, todo); + } + }); }, onCheckboxChanged: (complete) { - TodosBlocProvider.of(context) - .updateTodo - .add(todo.copyWith(complete: !todo.complete)); + TodosBlocProvider.of( + context, + ).updateTodo.add(todo.copyWith(complete: !todo.complete)); }, ); }, @@ -87,6 +85,6 @@ class TodoList extends StatelessWidget { ), ); - Scaffold.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(context).showSnackBar(snackBar); } } diff --git a/bloc_flutter/lib/widgets/todos_bloc_provider.dart b/bloc_flutter/lib/widgets/todos_bloc_provider.dart index 37103758..dfbf41b3 100644 --- a/bloc_flutter/lib/widgets/todos_bloc_provider.dart +++ b/bloc_flutter/lib/widgets/todos_bloc_provider.dart @@ -1,29 +1,23 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:blocs/blocs.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; class TodosBlocProvider extends StatefulWidget { final Widget child; final TodosListBloc bloc; - TodosBlocProvider({Key key, @required this.child, @required this.bloc}) - : super(key: key); + const TodosBlocProvider({super.key, required this.child, required this.bloc}); @override - _TodosBlocProviderState createState() => _TodosBlocProviderState(); + TodosBlocProviderState createState() => TodosBlocProviderState(); static TodosListBloc of(BuildContext context) { return context - .dependOnInheritedWidgetOfExactType<_TodosBlocProvider>() + .dependOnInheritedWidgetOfExactType<_TodosBlocProvider>()! .bloc; } } -class _TodosBlocProviderState extends State { +class TodosBlocProviderState extends State { @override Widget build(BuildContext context) { return _TodosBlocProvider(bloc: widget.bloc, child: widget.child); @@ -39,11 +33,7 @@ class _TodosBlocProviderState extends State { class _TodosBlocProvider extends InheritedWidget { final TodosListBloc bloc; - _TodosBlocProvider({ - Key key, - @required this.bloc, - @required Widget child, - }) : super(key: key, child: child); + const _TodosBlocProvider({required this.bloc, required super.child}); @override bool updateShouldNotify(_TodosBlocProvider old) => bloc != old.bloc; diff --git a/bloc_flutter/linux/.gitignore b/bloc_flutter/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/bloc_flutter/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/bloc_flutter/linux/CMakeLists.txt b/bloc_flutter/linux/CMakeLists.txt new file mode 100644 index 00000000..6f4ebf4e --- /dev/null +++ b/bloc_flutter/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +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 "bloc_flutter_sample") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.bloc_flutter_sample") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +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() + +# 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() + +# 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_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# 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 +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# 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() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +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) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/bloc_flutter/linux/flutter/CMakeLists.txt b/bloc_flutter/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/bloc_flutter/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +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. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# 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/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter 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. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/bloc_flutter/linux/flutter/generated_plugin_registrant.cc b/bloc_flutter/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e71a16d2 --- /dev/null +++ b/bloc_flutter/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/bloc_flutter/linux/flutter/generated_plugin_registrant.h b/bloc_flutter/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/bloc_flutter/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/bloc_flutter/linux/flutter/generated_plugins.cmake b/bloc_flutter/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/bloc_flutter/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + 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}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/bloc_flutter/linux/runner/CMakeLists.txt b/bloc_flutter/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/bloc_flutter/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "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 +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/bloc_flutter/linux/runner/main.cc b/bloc_flutter/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/bloc_flutter/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/bloc_flutter/linux/runner/my_application.cc b/bloc_flutter/linux/runner/my_application.cc new file mode 100644 index 00000000..4a792229 --- /dev/null +++ b/bloc_flutter/linux/runner/my_application.cc @@ -0,0 +1,144 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView *view) +{ + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // 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 + // desktop). + // 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. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "bloc_flutter_sample"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "bloc_flutter_sample"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/bloc_flutter/linux/runner/my_application.h b/bloc_flutter/linux/runner/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/bloc_flutter/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/bloc_flutter/macos/.gitignore b/bloc_flutter/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/bloc_flutter/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/bloc_flutter/macos/Flutter/Flutter-Debug.xcconfig b/bloc_flutter/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/bloc_flutter/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/bloc_flutter/macos/Flutter/Flutter-Release.xcconfig b/bloc_flutter/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/bloc_flutter/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/bloc_flutter/macos/Flutter/GeneratedPluginRegistrant.swift b/bloc_flutter/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b8e2b22f --- /dev/null +++ b/bloc_flutter/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/bloc_flutter/macos/Podfile b/bloc_flutter/macos/Podfile new file mode 100644 index 00000000..ff5ddb3b --- /dev/null +++ b/bloc_flutter/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/bloc_flutter/macos/Runner.xcodeproj/project.pbxproj b/bloc_flutter/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..5a57ad02 --- /dev/null +++ b/bloc_flutter/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,705 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* bloc_flutter_sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "bloc_flutter_sample.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* bloc_flutter_sample.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* bloc_flutter_sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bloc_flutter_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bloc_flutter_sample"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bloc_flutter_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bloc_flutter_sample"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bloc_flutter_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bloc_flutter_sample"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/bloc_flutter/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/bloc_flutter/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/bloc_flutter/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/bloc_flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/bloc_flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..0c6d28c2 --- /dev/null +++ b/bloc_flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/built_redux/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/bloc_flutter/macos/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from built_redux/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to bloc_flutter/macos/Runner.xcworkspace/contents.xcworkspacedata diff --git a/bloc_flutter/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/bloc_flutter/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/bloc_flutter/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/bloc_flutter/macos/Runner/AppDelegate.swift b/bloc_flutter/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/bloc_flutter/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/bloc_flutter/macos/Runner/Base.lproj/MainMenu.xib b/bloc_flutter/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/bloc_flutter/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bloc_flutter/macos/Runner/Configs/AppInfo.xcconfig b/bloc_flutter/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..50b414d2 --- /dev/null +++ b/bloc_flutter/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// 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 +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = bloc_flutter_sample + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.blocFlutterSample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/bloc_flutter/macos/Runner/Configs/Debug.xcconfig b/bloc_flutter/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/bloc_flutter/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/bloc_flutter/macos/Runner/Configs/Release.xcconfig b/bloc_flutter/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/bloc_flutter/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/bloc_flutter/macos/Runner/Configs/Warnings.xcconfig b/bloc_flutter/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/bloc_flutter/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/bloc_flutter/macos/Runner/DebugProfile.entitlements b/bloc_flutter/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/bloc_flutter/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/bloc_flutter/macos/Runner/Info.plist b/bloc_flutter/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/bloc_flutter/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/bloc_flutter/macos/Runner/MainFlutterWindow.swift b/bloc_flutter/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/bloc_flutter/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/bloc_flutter/macos/Runner/Release.entitlements b/bloc_flutter/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/bloc_flutter/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/bloc_flutter/macos/RunnerTests/RunnerTests.swift b/bloc_flutter/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/bloc_flutter/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/bloc_flutter/pubspec.yaml b/bloc_flutter/pubspec.yaml index 559b2d60..13e379fa 100644 --- a/bloc_flutter/pubspec.yaml +++ b/bloc_flutter/pubspec.yaml @@ -12,33 +12,34 @@ description: A new Flutter project. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html version: 1.0.0+1 +publish_to: "none" environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ^3.9.0 dependencies: flutter: sdk: flutter - todos_repository_local_storage: - path: ../todos_repository_local_storage - firebase_flutter_repository: - path: ../firebase_flutter_repository todos_app_core: path: ../todos_app_core + todos_repository_core: + path: ../todos_repository_core + todos_repository_local_storage: + path: ../todos_repository_local_storage blocs: path: ../blocs - rxdart: ^0.23.1 - key_value_store_flutter: - key_value_store_web: + rxdart: ^0.28.0 shared_preferences: dev_dependencies: + flutter_lints: flutter_test: sdk: flutter - flutter_driver: + integration_test: sdk: flutter test: mockito: + build_runner: integration_tests: path: ../integration_tests @@ -47,7 +48,6 @@ dev_dependencies: # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. diff --git a/bloc_flutter/test/home_screen_test.dart b/bloc_flutter/test/home_screen_test.dart new file mode 100644 index 00000000..55bcf018 --- /dev/null +++ b/bloc_flutter/test/home_screen_test.dart @@ -0,0 +1,171 @@ +import 'package:bloc_flutter_sample/anonymous_user_repository.dart'; +import 'package:bloc_flutter_sample/dependency_injection.dart'; +import 'package:bloc_flutter_sample/localization.dart'; +import 'package:bloc_flutter_sample/screens/home_screen.dart'; +import 'package:bloc_flutter_sample/widgets/todos_bloc_provider.dart'; +import 'package:blocs/blocs.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:todos_app_core/todos_app_core.dart'; +import 'package:todos_repository_core/todos_repository_core.dart'; + +import 'home_screen_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec(), MockSpec()]) +void main() { + group('HomeScreen', () { + final todoListFinder = find.byKey(ArchSampleKeys.todoList); + final todoItem1Finder = find.byKey(ArchSampleKeys.todoItem('1')); + final todoItem2Finder = find.byKey(ArchSampleKeys.todoItem('2')); + final todoItem3Finder = find.byKey(ArchSampleKeys.todoItem('3')); + + testWidgets('should render loading indicator at first', (tester) async { + await tester.pumpWidget( + _TestWidget( + todosInteractor: MockTodosInteractor(), + userRepository: AnonymousUserRepository(), + ), + ); + await tester.pump(Duration.zero); + + expect(find.byKey(ArchSampleKeys.todosLoading), findsOneWidget); + }); + + testWidgets('should display a list after loading todos', (tester) async { + final handle = tester.ensureSemantics(); + final interactor = MockTodosInteractor(); + + when( + interactor.todos, + ).thenAnswer((_) => Stream.fromIterable([_TestWidget._defaultTodos])); + + await tester.pumpWidget( + _TestWidget( + todosInteractor: interactor, + userRepository: AnonymousUserRepository(), + ), + ); + await tester.pumpAndSettle(); + + final checkbox1 = find.descendant( + of: find.byKey(ArchSampleKeys.todoItemCheckbox('1')), + matching: find.byType(Focus), + ); + final checkbox2 = find.descendant( + of: find.byKey(ArchSampleKeys.todoItemCheckbox('2')), + matching: find.byType(Focus), + ); + final checkbox3 = find.descendant( + of: find.byKey(ArchSampleKeys.todoItemCheckbox('3')), + matching: find.byType(Focus), + ); + + expect(todoListFinder, findsOneWidget); + expect(todoItem1Finder, findsOneWidget); + expect(find.text('T1'), findsOneWidget); + expect(find.text('N1'), findsOneWidget); + expect(tester.getSemantics(checkbox1), isChecked(false)); + expect(todoItem2Finder, findsOneWidget); + expect(find.text('T2'), findsOneWidget); + expect(tester.getSemantics(checkbox2), isChecked(false)); + expect(todoItem3Finder, findsOneWidget); + expect(find.text('T3'), findsOneWidget); + expect(tester.getSemantics(checkbox3), isChecked(true)); + + handle.dispose(); + }); + + testWidgets('should remove todos using a dismissible', (tester) async { + final interactor = MockTodosInteractor(); + + when( + interactor.todos, + ).thenAnswer((_) => Stream.fromIterable([_TestWidget._defaultTodos])); + + await tester.pumpWidget( + _TestWidget( + todosInteractor: interactor, + userRepository: AnonymousUserRepository(), + ), + ); + await tester.pumpAndSettle(); + await tester.drag(todoItem1Finder, Offset(-1000, 0)); + await tester.pumpAndSettle(Duration(seconds: 5)); + + expect(todoItem1Finder, findsNothing); + expect(todoItem2Finder, findsOneWidget); + expect(todoItem3Finder, findsOneWidget); + }); + + testWidgets('should display stats when switching tabs', (tester) async { + final interactor = MockTodosInteractor(); + + when( + interactor.todos, + ).thenAnswer((_) => Stream.fromIterable([_TestWidget._defaultTodos])); + + await tester.pumpWidget( + _TestWidget( + todosInteractor: interactor, + userRepository: AnonymousUserRepository(), + ), + ); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(ArchSampleKeys.statsTab)); + await tester.pump(); + + expect(find.byKey(ArchSampleKeys.statsNumActive), findsOneWidget); + expect(find.byKey(ArchSampleKeys.statsNumActive), findsOneWidget); + }); + }); +} + +class _TestWidget extends StatelessWidget { + const _TestWidget({ + required this.todosInteractor, + required this.userRepository, + }); + + final TodosInteractor todosInteractor; + final UserRepository userRepository; + + @override + Widget build(BuildContext context) { + return Injector( + todosInteractor: todosInteractor, + userRepository: userRepository, + child: TodosBlocProvider( + bloc: TodosListBloc(todosInteractor), + child: MaterialApp( + localizationsDelegates: [ + BlocLocalizationsDelegate(), + ArchSampleLocalizationsDelegate(), + ], + home: HomeScreen(userRepository: userRepository), + ), + ), + ); + } + + static List get _defaultTodos { + return [ + Todo('T1', id: '1', note: 'N1'), + Todo('T2', id: '2'), + Todo('T3', id: '3', complete: true), + ]; + } +} + +Matcher isChecked(bool isChecked) { + return matchesSemantics( + isChecked: isChecked, + hasTapAction: true, + hasFocusAction: true, + hasCheckedState: true, + isFocusable: true, + hasEnabledState: true, + isEnabled: true, + ); +} diff --git a/bloc_flutter/test/home_screen_test.mocks.dart b/bloc_flutter/test/home_screen_test.mocks.dart new file mode 100644 index 00000000..2c51ada1 --- /dev/null +++ b/bloc_flutter/test/home_screen_test.mocks.dart @@ -0,0 +1,156 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in bloc_flutter_sample/test/home_screen_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; + +import 'package:blocs/blocs.dart' as _i3; +import 'package:mockito/mockito.dart' as _i1; +import 'package:todos_repository_core/todos_repository_core.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeReactiveTodosRepository_0 extends _i1.SmartFake + implements _i2.ReactiveTodosRepository { + _FakeReactiveTodosRepository_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakeUserEntity_1 extends _i1.SmartFake implements _i2.UserEntity { + _FakeUserEntity_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [TodosInteractor]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodosInteractor extends _i1.Mock implements _i3.TodosInteractor { + @override + _i2.ReactiveTodosRepository get repository => + (super.noSuchMethod( + Invocation.getter(#repository), + returnValue: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + returnValueForMissingStub: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + ) + as _i2.ReactiveTodosRepository); + + @override + _i4.Stream> get todos => + (super.noSuchMethod( + Invocation.getter(#todos), + returnValue: _i4.Stream>.empty(), + returnValueForMissingStub: _i4.Stream>.empty(), + ) + as _i4.Stream>); + + @override + _i4.Stream get allComplete => + (super.noSuchMethod( + Invocation.getter(#allComplete), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream get hasCompletedTodos => + (super.noSuchMethod( + Invocation.getter(#hasCompletedTodos), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream<_i3.Todo> todo(String? id) => + (super.noSuchMethod( + Invocation.method(#todo, [id]), + returnValue: _i4.Stream<_i3.Todo>.empty(), + returnValueForMissingStub: _i4.Stream<_i3.Todo>.empty(), + ) + as _i4.Stream<_i3.Todo>); + + @override + _i4.Future updateTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future addNewTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future deleteTodo(String? id) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [id]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future clearCompleted([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#clearCompleted, [_0]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future> toggleAll([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#toggleAll, [_0]), + returnValue: _i4.Future>.value([]), + returnValueForMissingStub: _i4.Future>.value( + [], + ), + ) + as _i4.Future>); +} + +/// A class which mocks [UserRepository]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockUserRepository extends _i1.Mock implements _i2.UserRepository { + @override + _i4.Future<_i2.UserEntity> login() => + (super.noSuchMethod( + Invocation.method(#login, []), + returnValue: _i4.Future<_i2.UserEntity>.value( + _FakeUserEntity_1(this, Invocation.method(#login, [])), + ), + returnValueForMissingStub: _i4.Future<_i2.UserEntity>.value( + _FakeUserEntity_1(this, Invocation.method(#login, [])), + ), + ) + as _i4.Future<_i2.UserEntity>); +} diff --git a/bloc_flutter/test_driver/integration_test.dart b/bloc_flutter/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/bloc_flutter/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/bloc_flutter/test_driver/todo_app.dart b/bloc_flutter/test_driver/todo_app.dart deleted file mode 100644 index 5822c6d9..00000000 --- a/bloc_flutter/test_driver/todo_app.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// This line imports the extension -import 'package:bloc_flutter_sample/main.dart' as app; -import 'package:flutter_driver/driver_extension.dart'; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/bloc_flutter/test_driver/todo_app_test.dart b/bloc_flutter/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/bloc_flutter/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/bloc_flutter/web/favicon.png b/bloc_flutter/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/bloc_flutter/web/favicon.png differ diff --git a/bloc_flutter/web/icons/Icon-192.png b/bloc_flutter/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/bloc_flutter/web/icons/Icon-192.png differ diff --git a/bloc_flutter/web/icons/Icon-512.png b/bloc_flutter/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/bloc_flutter/web/icons/Icon-512.png differ diff --git a/bloc_flutter/web/icons/Icon-maskable-192.png b/bloc_flutter/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/bloc_flutter/web/icons/Icon-maskable-192.png differ diff --git a/bloc_flutter/web/icons/Icon-maskable-512.png b/bloc_flutter/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/bloc_flutter/web/icons/Icon-maskable-512.png differ diff --git a/bloc_flutter/web/index.html b/bloc_flutter/web/index.html index f99ea3a2..f9cba26a 100644 --- a/bloc_flutter/web/index.html +++ b/bloc_flutter/web/index.html @@ -1,10 +1,38 @@ + + + - bloc_flutter + + + + + + + + + + + + + bloc_flutter_sample + - + diff --git a/bloc_flutter/web/manifest.json b/bloc_flutter/web/manifest.json new file mode 100644 index 00000000..f6c0c9b8 --- /dev/null +++ b/bloc_flutter/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "bloc_flutter_sample", + "short_name": "bloc_flutter_sample", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/bloc_flutter/windows/.gitignore b/bloc_flutter/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/bloc_flutter/windows/.gitignore @@ -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/ diff --git a/bloc_flutter/windows/CMakeLists.txt b/bloc_flutter/windows/CMakeLists.txt new file mode 100644 index 00000000..7dd441e9 --- /dev/null +++ b/bloc_flutter/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(bloc_flutter_sample 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 "bloc_flutter_sample") + +# 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) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_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 "$") +# 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) diff --git a/bloc_flutter/windows/flutter/CMakeLists.txt b/bloc_flutter/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/bloc_flutter/windows/flutter/CMakeLists.txt @@ -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} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/bloc_flutter/windows/flutter/generated_plugin_registrant.cc b/bloc_flutter/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/bloc_flutter/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/bloc_flutter/windows/flutter/generated_plugin_registrant.h b/bloc_flutter/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/bloc_flutter/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/bloc_flutter/windows/flutter/generated_plugins.cmake b/bloc_flutter/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/bloc_flutter/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +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 $) + 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) diff --git a/bloc_flutter/windows/runner/CMakeLists.txt b/bloc_flutter/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/bloc_flutter/windows/runner/CMakeLists.txt @@ -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) diff --git a/bloc_flutter/windows/runner/Runner.rc b/bloc_flutter/windows/runner/Runner.rc new file mode 100644 index 00000000..aa6f7091 --- /dev/null +++ b/bloc_flutter/windows/runner/Runner.rc @@ -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", "com.example" "\0" + VALUE "FileDescription", "bloc_flutter_sample" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "bloc_flutter_sample" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "bloc_flutter_sample.exe" "\0" + VALUE "ProductName", "bloc_flutter_sample" "\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 diff --git a/bloc_flutter/windows/runner/flutter_window.cpp b/bloc_flutter/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/bloc_flutter/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#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( + 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 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); +} diff --git a/bloc_flutter/windows/runner/flutter_window.h b/bloc_flutter/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/bloc_flutter/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#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_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/bloc_flutter/windows/runner/main.cpp b/bloc_flutter/windows/runner/main.cpp new file mode 100644 index 00000000..a26af59f --- /dev/null +++ b/bloc_flutter/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 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"bloc_flutter_sample", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/bloc_flutter/windows/runner/resource.h b/bloc_flutter/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/bloc_flutter/windows/runner/resource.h @@ -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 diff --git a/bloc_flutter/windows/runner/resources/app_icon.ico b/bloc_flutter/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/bloc_flutter/windows/runner/resources/app_icon.ico differ diff --git a/bloc_flutter/windows/runner/runner.exe.manifest b/bloc_flutter/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/bloc_flutter/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/bloc_flutter/windows/runner/utils.cpp b/bloc_flutter/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/bloc_flutter/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +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 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::vector 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; +} diff --git a/bloc_flutter/windows/runner/utils.h b/bloc_flutter/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/bloc_flutter/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// 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, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/bloc_flutter/windows/runner/win32_window.cpp b/bloc_flutter/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/bloc_flutter/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#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(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( + 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(origin.x), + static_cast(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(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(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(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( + 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)); + } +} diff --git a/bloc_flutter/windows/runner/win32_window.h b/bloc_flutter/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/bloc_flutter/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// 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_ diff --git a/bloc_library/.metadata b/bloc_library/.metadata index 1b5cec02..05a8ab44 100644 --- a/bloc_library/.metadata +++ b/bloc_library/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: 27321ebbad34b0a3fafe99fac037102196d655ff - channel: stable + revision: "05db9689081f091050f01aed79f04dce0c750154" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: android + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: ios + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: linux + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: macos + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: web + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: windows + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/bloc_library/analysis_options.yaml b/bloc_library/analysis_options.yaml new file mode 100644 index 00000000..134f2137 --- /dev/null +++ b/bloc_library/analysis_options.yaml @@ -0,0 +1,34 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# 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 +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + # The lint rules applied to this project can be customized in the + # 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 + # and their documentation is published at https://dart.dev/lints. + # + # 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 + # 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 + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/bloc_library/android/app/build.gradle.kts b/bloc_library/android/app/build.gradle.kts new file mode 100644 index 00000000..fd6e34c9 --- /dev/null +++ b/bloc_library/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.bloc_library" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.bloc_library" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/bloc_library/android/app/src/main/res/drawable-v21/launch_background.xml b/bloc_library/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/bloc_library/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/bloc_library/android/app/src/main/res/values-night/styles.xml b/bloc_library/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/bloc_library/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/bloc_library/android/build.gradle.kts b/bloc_library/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/bloc_library/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/bloc_library/android/settings.gradle.kts b/bloc_library/android/settings.gradle.kts new file mode 100644 index 00000000..fb605bc8 --- /dev/null +++ b/bloc_library/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/bloc_library/integration_test/app_test.dart b/bloc_library/integration_test/app_test.dart new file mode 100644 index 00000000..6af7a098 --- /dev/null +++ b/bloc_library/integration_test/app_test.dart @@ -0,0 +1,19 @@ +import 'package:bloc_library/app.dart'; +import 'package:integration_tests/integration_tests.dart' as integration_tests; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; + +void main() { + integration_tests.run( + appBuilder: () async { + return TodosApp( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'bloc_library_test_${DateTime.now().toIso8601String()}', + await SharedPreferences.getInstance(), + ), + ), + ); + }, + ); +} diff --git a/bloc_library/ios/Flutter/ephemeral/flutter_lldb_helper.py b/bloc_library/ios/Flutter/ephemeral/flutter_lldb_helper.py new file mode 100644 index 00000000..a88caf99 --- /dev/null +++ b/bloc_library/ios/Flutter/ephemeral/flutter_lldb_helper.py @@ -0,0 +1,32 @@ +# +# Generated file, do not edit. +# + +import lldb + +def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict): + """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages.""" + base = frame.register["x0"].GetValueAsAddress() + page_len = frame.register["x1"].GetValueAsUnsigned() + + # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the + # first page to see if handled it correctly. This makes diagnosing + # misconfiguration (e.g. missing breakpoint) easier. + data = bytearray(page_len) + data[0:8] = b'IHELPED!' + + error = lldb.SBError() + frame.GetThread().GetProcess().WriteMemory(base, data, error) + if not error.Success(): + print(f'Failed to write into {base}[+{page_len}]', error) + return + +def __lldb_init_module(debugger: lldb.SBDebugger, _): + target = debugger.GetDummyTarget() + # Caveat: must use BreakpointCreateByRegEx here and not + # BreakpointCreateByName. For some reasons callback function does not + # get carried over from dummy target for the later. + bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$") + bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__)) + bp.SetAutoContinue(True) + print("-- LLDB integration loaded --") diff --git a/bloc_library/ios/Flutter/ephemeral/flutter_lldbinit b/bloc_library/ios/Flutter/ephemeral/flutter_lldbinit new file mode 100644 index 00000000..e3ba6fbe --- /dev/null +++ b/bloc_library/ios/Flutter/ephemeral/flutter_lldbinit @@ -0,0 +1,5 @@ +# +# Generated file, do not edit. +# + +command script import --relative-to-command-file flutter_lldb_helper.py diff --git a/bloc_library/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/bloc_library/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/bloc_library/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/bloc_library/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/bloc_library/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/bloc_library/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/bloc_library/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/bloc_library/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/bloc_library/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/bloc_library/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/bloc_library/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/bloc_library/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/bloc_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/bloc_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/bloc_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/bloc_library/ios/RunnerTests/RunnerTests.swift b/bloc_library/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/bloc_library/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/bloc_library/lib/app.dart b/bloc_library/lib/app.dart new file mode 100644 index 00000000..d8e2d1f9 --- /dev/null +++ b/bloc_library/lib/app.dart @@ -0,0 +1,63 @@ +import 'package:bloc_library/blocs/blocs.dart'; +import 'package:bloc_library/localization.dart'; +import 'package:bloc_library/models/models.dart'; +import 'package:bloc_library/screens/screens.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:todos_app_core/todos_app_core.dart'; +import 'package:todos_repository_core/todos_repository_core.dart'; + +class TodosApp extends StatelessWidget { + const TodosApp({super.key, required this.repository}); + + final TodosRepository repository; + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) { + return TodosBloc(todosRepository: repository)..add(LoadTodos()); + }, + child: MaterialApp( + onGenerateTitle: (context) => + FlutterBlocLocalizations.of(context).appTitle, + theme: ArchSampleTheme.lightTheme, + darkTheme: ArchSampleTheme.darkTheme, + localizationsDelegates: [ + ArchSampleLocalizationsDelegate(), + FlutterBlocLocalizationsDelegate(), + ], + routes: { + ArchSampleRoutes.home: (context) { + return MultiBlocProvider( + providers: [ + BlocProvider(create: (context) => TabBloc()), + BlocProvider( + create: (context) => FilteredTodosBloc( + todosBloc: BlocProvider.of(context), + ), + ), + BlocProvider( + create: (context) => + StatsBloc(todosBloc: BlocProvider.of(context)), + ), + ], + child: HomeScreen(), + ); + }, + ArchSampleRoutes.addTodo: (context) { + return AddEditScreen( + key: ArchSampleKeys.addTodoScreen, + onSave: (task, note) { + BlocProvider.of( + context, + ).add(AddTodo(Todo(task, note: note))); + }, + isEditing: false, + ); + }, + }, + ), + ); + } +} diff --git a/bloc_library/lib/bloc_library_keys.dart b/bloc_library/lib/bloc_library_keys.dart index 79cabe6a..81bab004 100644 --- a/bloc_library/lib/bloc_library_keys.dart +++ b/bloc_library/lib/bloc_library_keys.dart @@ -1,16 +1,15 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/widgets.dart'; class BlocLibraryKeys { - static final extraActionsPopupMenuButton = - const Key('__extraActionsPopupMenuButton__'); - static final extraActionsEmptyContainer = - const Key('__extraActionsEmptyContainer__'); - static final filteredTodosEmptyContainer = - const Key('__filteredTodosEmptyContainer__'); + static final extraActionsPopupMenuButton = const Key( + '__extraActionsPopupMenuButton__', + ); + static final extraActionsEmptyContainer = const Key( + '__extraActionsEmptyContainer__', + ); + static final filteredTodosEmptyContainer = const Key( + '__filteredTodosEmptyContainer__', + ); static final statsLoadingIndicator = const Key('__statsLoadingIndicator__'); static final emptyStatsContainer = const Key('__emptyStatsContainer__'); static final emptyDetailsContainer = const Key('__emptyDetailsContainer__'); diff --git a/bloc_library/lib/blocs/blocs.dart b/bloc_library/lib/blocs/blocs.dart index b4e836a2..c749033b 100644 --- a/bloc_library/lib/blocs/blocs.dart +++ b/bloc_library/lib/blocs/blocs.dart @@ -1,9 +1,5 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - export './filtered_todos/filtered_todos.dart'; export './stats/stats.dart'; export './tab/tab.dart'; export './todos/todos.dart'; -export './simple_bloc_delegate.dart'; +export 'simple_bloc_observer.dart'; diff --git a/bloc_library/lib/blocs/filtered_todos/filtered_todos.dart b/bloc_library/lib/blocs/filtered_todos/filtered_todos.dart index 2dab7174..f15a9590 100644 --- a/bloc_library/lib/blocs/filtered_todos/filtered_todos.dart +++ b/bloc_library/lib/blocs/filtered_todos/filtered_todos.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - export './filtered_todos_bloc.dart'; export './filtered_todos_event.dart'; export './filtered_todos_state.dart'; diff --git a/bloc_library/lib/blocs/filtered_todos/filtered_todos_bloc.dart b/bloc_library/lib/blocs/filtered_todos/filtered_todos_bloc.dart index 19f268c8..7351cd60 100644 --- a/bloc_library/lib/blocs/filtered_todos/filtered_todos_bloc.dart +++ b/bloc_library/lib/blocs/filtered_todos/filtered_todos_bloc.dart @@ -1,71 +1,60 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; + import 'package:bloc/bloc.dart'; -import 'package:meta/meta.dart'; import 'package:bloc_library/blocs/filtered_todos/filtered_todos.dart'; import 'package:bloc_library/blocs/todos/todos.dart'; import 'package:bloc_library/models/models.dart'; class FilteredTodosBloc extends Bloc { final TodosBloc todosBloc; - StreamSubscription todosSubscription; + late final StreamSubscription todosSubscription; - FilteredTodosBloc({@required this.todosBloc}) { - todosSubscription = todosBloc.listen((state) { + FilteredTodosBloc({required this.todosBloc}) + : super( + todosBloc.state is TodosLoaded + ? FilteredTodosLoaded( + (todosBloc.state as TodosLoaded).todos, + VisibilityFilter.all, + ) + : FilteredTodosLoading(), + ) { + todosSubscription = todosBloc.stream.listen((state) { if (state is TodosLoaded) { add(UpdateTodos(state.todos)); } }); - } - - @override - FilteredTodosState get initialState { - return todosBloc.state is TodosLoaded - ? FilteredTodosLoaded( - (todosBloc.state as TodosLoaded).todos, - VisibilityFilter.all, - ) - : FilteredTodosLoading(); - } - @override - Stream mapEventToState(FilteredTodosEvent event) async* { - if (event is UpdateFilter) { - yield* _mapUpdateFilterToState(event); - } else if (event is UpdateTodos) { - yield* _mapTodosUpdatedToState(event); - } + on(_onUpdateFilter); + on(_onUpdateTodos); } - Stream _mapUpdateFilterToState( - UpdateFilter event, - ) async* { + void _onUpdateFilter(UpdateFilter event, Emitter emit) { if (todosBloc.state is TodosLoaded) { - yield FilteredTodosLoaded( - _mapTodosToFilteredTodos( - (todosBloc.state as TodosLoaded).todos, + emit( + FilteredTodosLoaded( + _mapTodosToFilteredTodos( + (todosBloc.state as TodosLoaded).todos, + event.filter, + ), event.filter, ), - event.filter, ); } } - Stream _mapTodosUpdatedToState( - UpdateTodos event, - ) async* { + void _onUpdateTodos(UpdateTodos event, Emitter emit) { final visibilityFilter = state is FilteredTodosLoaded ? (state as FilteredTodosLoaded).activeFilter : VisibilityFilter.all; - yield FilteredTodosLoaded( - _mapTodosToFilteredTodos( - (todosBloc.state as TodosLoaded).todos, + + emit( + FilteredTodosLoaded( + _mapTodosToFilteredTodos( + (todosBloc.state as TodosLoaded).todos, + visibilityFilter, + ), visibilityFilter, ), - visibilityFilter, ); } @@ -86,7 +75,7 @@ class FilteredTodosBloc extends Bloc { @override Future close() { - todosSubscription?.cancel(); + todosSubscription.cancel(); return super.close(); } } diff --git a/bloc_library/lib/blocs/filtered_todos/filtered_todos_event.dart b/bloc_library/lib/blocs/filtered_todos/filtered_todos_event.dart index 24ff55d8..7a07f880 100644 --- a/bloc_library/lib/blocs/filtered_todos/filtered_todos_event.dart +++ b/bloc_library/lib/blocs/filtered_todos/filtered_todos_event.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:equatable/equatable.dart'; import 'package:bloc_library/models/models.dart'; diff --git a/bloc_library/lib/blocs/filtered_todos/filtered_todos_state.dart b/bloc_library/lib/blocs/filtered_todos/filtered_todos_state.dart index 400d6172..89ec5158 100644 --- a/bloc_library/lib/blocs/filtered_todos/filtered_todos_state.dart +++ b/bloc_library/lib/blocs/filtered_todos/filtered_todos_state.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:equatable/equatable.dart'; import 'package:bloc_library/models/models.dart'; @@ -18,10 +14,7 @@ class FilteredTodosLoaded extends FilteredTodosState { final List filteredTodos; final VisibilityFilter activeFilter; - const FilteredTodosLoaded( - this.filteredTodos, - this.activeFilter, - ); + const FilteredTodosLoaded(this.filteredTodos, this.activeFilter); @override List get props => [filteredTodos, activeFilter]; diff --git a/bloc_library/lib/blocs/simple_bloc_delegate.dart b/bloc_library/lib/blocs/simple_bloc_delegate.dart deleted file mode 100644 index 334e2363..00000000 --- a/bloc_library/lib/blocs/simple_bloc_delegate.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:bloc/bloc.dart'; - -// We can extend `BlocDelegate` and override `onTransition` and `onError` -// in order to handle transitions and errors from all Blocs. -class SimpleBlocDelegate extends BlocDelegate { - @override - void onEvent(Bloc bloc, Object event) { - super.onEvent(bloc, event); - print(event); - } - - @override - void onTransition(Bloc bloc, Transition transition) { - super.onTransition(bloc, transition); - print(transition); - } - - @override - void onError(Bloc bloc, Object error, StackTrace stacktrace) { - super.onError(bloc, error, stacktrace); - print(error); - } -} diff --git a/bloc_library/lib/blocs/simple_bloc_observer.dart b/bloc_library/lib/blocs/simple_bloc_observer.dart new file mode 100644 index 00000000..d60bdab2 --- /dev/null +++ b/bloc_library/lib/blocs/simple_bloc_observer.dart @@ -0,0 +1,28 @@ +// ignore_for_file: avoid_print + +import 'package:bloc/bloc.dart'; + +// We can extend `BlocObserver` and override `onTransition` and `onError` +// in order to handle transitions and errors from all Blocs. +class SimpleBlocObserver extends BlocObserver { + @override + void onEvent(Bloc bloc, Object? event) { + super.onEvent(bloc, event); + print(event); + } + + @override + void onTransition( + Bloc bloc, + Transition transition, + ) { + super.onTransition(bloc, transition); + print(transition); + } + + @override + void onError(BlocBase bloc, Object error, StackTrace stackTrace) { + super.onError(bloc, error, stackTrace); + print(error); + } +} diff --git a/bloc_library/lib/blocs/stats/stats_bloc.dart b/bloc_library/lib/blocs/stats/stats_bloc.dart index e6b4ae77..dda9dac0 100644 --- a/bloc_library/lib/blocs/stats/stats_bloc.dart +++ b/bloc_library/lib/blocs/stats/stats_bloc.dart @@ -1,37 +1,41 @@ import 'dart:async'; -import 'package:meta/meta.dart'; + import 'package:bloc/bloc.dart'; import 'package:bloc_library/blocs/blocs.dart'; +import 'package:bloc_library/models/todo.dart'; class StatsBloc extends Bloc { final TodosBloc todosBloc; - StreamSubscription todosSubscription; + late final StreamSubscription todosSubscription; - StatsBloc({@required this.todosBloc}) { - todosSubscription = todosBloc.listen((state) { + StatsBloc({required this.todosBloc}) + : super( + todosBloc.state is TodosLoaded + ? _mapTodosToStats((todosBloc.state as TodosLoaded).todos) + : StatsLoading(), + ) { + todosSubscription = todosBloc.stream.listen((state) { if (state is TodosLoaded) { add(UpdateStats(state.todos)); } }); + + on(_onUpdateStats); } - @override - StatsState get initialState => StatsLoading(); + void _onUpdateStats(UpdateStats event, Emitter emit) { + emit(_mapTodosToStats(event.todos)); + } - @override - Stream mapEventToState(StatsEvent event) async* { - if (event is UpdateStats) { - var numActive = - event.todos.where((todo) => !todo.complete).toList().length; - var numCompleted = - event.todos.where((todo) => todo.complete).toList().length; - yield StatsLoaded(numActive, numCompleted); - } + static StatsLoaded _mapTodosToStats(List todos) { + var numActive = todos.where((todo) => !todo.complete).toList().length; + var numCompleted = todos.where((todo) => todo.complete).toList().length; + return StatsLoaded(numActive, numCompleted); } @override Future close() { - todosSubscription?.cancel(); + todosSubscription.cancel(); return super.close(); } } diff --git a/bloc_library/lib/blocs/tab/tab.dart b/bloc_library/lib/blocs/tab/tab.dart index 28f7b1ea..2d61e12b 100644 --- a/bloc_library/lib/blocs/tab/tab.dart +++ b/bloc_library/lib/blocs/tab/tab.dart @@ -1,6 +1,2 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - export 'tab_bloc.dart'; export 'tab_event.dart'; diff --git a/bloc_library/lib/blocs/tab/tab_bloc.dart b/bloc_library/lib/blocs/tab/tab_bloc.dart index bc5d8b8b..d98fefe1 100644 --- a/bloc_library/lib/blocs/tab/tab_bloc.dart +++ b/bloc_library/lib/blocs/tab/tab_bloc.dart @@ -1,21 +1,13 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - import 'package:bloc/bloc.dart'; import 'package:bloc_library/blocs/tab/tab.dart'; import 'package:bloc_library/models/models.dart'; class TabBloc extends Bloc { - @override - AppTab get initialState => AppTab.todos; + TabBloc() : super(AppTab.todos) { + on(_onUpdateTab); + } - @override - Stream mapEventToState(TabEvent event) async* { - if (event is UpdateTab) { - yield event.tab; - } + void _onUpdateTab(UpdateTab event, Emitter emit) { + emit(event.tab); } } diff --git a/bloc_library/lib/blocs/tab/tab_event.dart b/bloc_library/lib/blocs/tab/tab_event.dart index fe6e0a49..bf3a240c 100644 --- a/bloc_library/lib/blocs/tab/tab_event.dart +++ b/bloc_library/lib/blocs/tab/tab_event.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:equatable/equatable.dart'; import 'package:bloc_library/models/models.dart'; diff --git a/bloc_library/lib/blocs/todos/todos.dart b/bloc_library/lib/blocs/todos/todos.dart index 6ad36e3f..22d556dd 100644 --- a/bloc_library/lib/blocs/todos/todos.dart +++ b/bloc_library/lib/blocs/todos/todos.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - export 'todos_bloc.dart'; export 'todos_event.dart'; export 'todos_state.dart'; diff --git a/bloc_library/lib/blocs/todos/todos_bloc.dart b/bloc_library/lib/blocs/todos/todos_bloc.dart index ea1222a8..88f0681e 100644 --- a/bloc_library/lib/blocs/todos/todos_bloc.dart +++ b/bloc_library/lib/blocs/todos/todos_bloc.dart @@ -1,11 +1,6 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:bloc/bloc.dart'; -import 'package:meta/meta.dart'; import 'package:bloc_library/blocs/todos/todos.dart'; import 'package:bloc_library/models/models.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -13,92 +8,80 @@ import 'package:todos_repository_core/todos_repository_core.dart'; class TodosBloc extends Bloc { final TodosRepository todosRepository; - TodosBloc({@required this.todosRepository}); - - @override - TodosState get initialState => TodosLoading(); - - @override - Stream mapEventToState(TodosEvent event) async* { - if (event is LoadTodos) { - yield* _mapLoadTodosToState(); - } else if (event is AddTodo) { - yield* _mapAddTodoToState(event); - } else if (event is UpdateTodo) { - yield* _mapUpdateTodoToState(event); - } else if (event is DeleteTodo) { - yield* _mapDeleteTodoToState(event); - } else if (event is ToggleAll) { - yield* _mapToggleAllToState(); - } else if (event is ClearCompleted) { - yield* _mapClearCompletedToState(); - } + TodosBloc({required this.todosRepository}) : super(const TodosLoading()) { + on(_onLoadTodos); + on(_onAddTodo); + on(_onUpdateTodo); + on(_onDeleteTodo); + on(_onToggleAll); + on(_onClearCompleted); } - Stream _mapLoadTodosToState() async* { + Future _onLoadTodos(LoadTodos event, Emitter emit) async { try { final todos = await todosRepository.loadTodos(); - yield TodosLoaded( - todos.map(Todo.fromEntity).toList(), - ); + emit(TodosLoaded(todos.map(Todo.fromEntity).toList())); } catch (_) { - yield TodosNotLoaded(); + emit(TodosNotLoaded()); } } - Stream _mapAddTodoToState(AddTodo event) async* { + Future _onAddTodo(AddTodo event, Emitter emit) async { if (state is TodosLoaded) { final updatedTodos = List.from((state as TodosLoaded).todos) ..add(event.todo); - yield TodosLoaded(updatedTodos); + emit(TodosLoaded(updatedTodos)); await _saveTodos(updatedTodos); } } - Stream _mapUpdateTodoToState(UpdateTodo event) async* { + Future _onUpdateTodo(UpdateTodo event, Emitter emit) async { if (state is TodosLoaded) { final updatedTodos = (state as TodosLoaded).todos.map((todo) { return todo.id == event.updatedTodo.id ? event.updatedTodo : todo; }).toList(); - yield TodosLoaded(updatedTodos); + emit(TodosLoaded(updatedTodos)); await _saveTodos(updatedTodos); } } - Stream _mapDeleteTodoToState(DeleteTodo event) async* { + Future _onDeleteTodo(DeleteTodo event, Emitter emit) async { if (state is TodosLoaded) { - final updatedTodos = (state as TodosLoaded) - .todos + final updatedTodos = (state as TodosLoaded).todos .where((todo) => todo.id != event.todo.id) .toList(); - yield TodosLoaded(updatedTodos); + emit(TodosLoaded(updatedTodos)); await _saveTodos(updatedTodos); } } - Stream _mapToggleAllToState() async* { + Future _onToggleAll(ToggleAll event, Emitter emit) async { if (state is TodosLoaded) { - final allComplete = - (state as TodosLoaded).todos.every((todo) => todo.complete); - final updatedTodos = (state as TodosLoaded) - .todos + final allComplete = (state as TodosLoaded).todos.every( + (todo) => todo.complete, + ); + final updatedTodos = (state as TodosLoaded).todos .map((todo) => todo.copyWith(complete: !allComplete)) .toList(); - yield TodosLoaded(updatedTodos); + emit(TodosLoaded(updatedTodos)); await _saveTodos(updatedTodos); } } - Stream _mapClearCompletedToState() async* { + Future _onClearCompleted( + ClearCompleted event, + Emitter emit, + ) async { if (state is TodosLoaded) { - final updatedTodos = - (state as TodosLoaded).todos.where((todo) => !todo.complete).toList(); - yield TodosLoaded(updatedTodos); + final updatedTodos = (state as TodosLoaded).todos + .where((todo) => !todo.complete) + .toList(); + emit(TodosLoaded(updatedTodos)); await _saveTodos(updatedTodos); } } - Future _saveTodos(List todos) { + Future _saveTodos(List todos) { return todosRepository.saveTodos( todos.map((todo) => todo.toEntity()).toList(), ); diff --git a/bloc_library/lib/blocs/todos/todos_event.dart b/bloc_library/lib/blocs/todos/todos_event.dart index ab18d06d..d403e0ee 100644 --- a/bloc_library/lib/blocs/todos/todos_event.dart +++ b/bloc_library/lib/blocs/todos/todos_event.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:equatable/equatable.dart'; import 'package:bloc_library/models/models.dart'; diff --git a/bloc_library/lib/blocs/todos/todos_state.dart b/bloc_library/lib/blocs/todos/todos_state.dart index 79334039..a35de235 100644 --- a/bloc_library/lib/blocs/todos/todos_state.dart +++ b/bloc_library/lib/blocs/todos/todos_state.dart @@ -1,9 +1,5 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:equatable/equatable.dart'; import 'package:bloc_library/models/models.dart'; +import 'package:equatable/equatable.dart'; abstract class TodosState extends Equatable { const TodosState(); @@ -12,7 +8,9 @@ abstract class TodosState extends Equatable { List get props => []; } -class TodosLoading extends TodosState {} +class TodosLoading extends TodosState { + const TodosLoading(); +} class TodosLoaded extends TodosState { final List todos; diff --git a/bloc_library/lib/localization.dart b/bloc_library/lib/localization.dart index 3ccb24e3..61aae636 100644 --- a/bloc_library/lib/localization.dart +++ b/bloc_library/lib/localization.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; @@ -11,7 +7,7 @@ class FlutterBlocLocalizations { return Localizations.of( context, FlutterBlocLocalizations, - ); + )!; } String get appTitle => 'Bloc Library Example'; diff --git a/bloc_library/lib/main.dart b/bloc_library/lib/main.dart index 4ba559f3..fdbfa43b 100644 --- a/bloc_library/lib/main.dart +++ b/bloc_library/lib/main.dart @@ -1,16 +1,26 @@ -import 'package:bloc_library/run_app.dart'; +import 'package:bloc/bloc.dart'; +import 'package:bloc_library/app.dart'; +import 'package:bloc_library/blocs/simple_bloc_observer.dart'; import 'package:flutter/cupertino.dart'; -import 'package:key_value_store_flutter/key_value_store_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - runBlocLibraryApp(LocalStorageRepository( - localStorage: KeyValueStorage( - 'bloc_library', - FlutterKeyValueStore(await SharedPreferences.getInstance()), + // BlocObserver oversees Blocs and delegates to BlocDelegate. + // We can set the BlocSupervisor's delegate to an instance of `SimpleBlocDelegate`. + // This will allow us to handle all transitions and errors in SimpleBlocDelegate. + Bloc.observer = SimpleBlocObserver(); + + runApp( + TodosApp( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'bloc_library', + await SharedPreferences.getInstance(), + ), + ), ), - )); + ); } diff --git a/bloc_library/lib/main_web.dart b/bloc_library/lib/main_web.dart deleted file mode 100644 index 8d500a2d..00000000 --- a/bloc_library/lib/main_web.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'dart:html'; - -import 'package:bloc_library/run_app.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:key_value_store_web/key_value_store_web.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - runBlocLibraryApp(LocalStorageRepository( - localStorage: KeyValueStorage( - 'bloc_library', - WebKeyValueStore(window.localStorage), - ), - )); -} diff --git a/bloc_library/lib/models/app_tab.dart b/bloc_library/lib/models/app_tab.dart index 096b6f56..8348dfcf 100644 --- a/bloc_library/lib/models/app_tab.dart +++ b/bloc_library/lib/models/app_tab.dart @@ -1,5 +1 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - enum AppTab { todos, stats } diff --git a/bloc_library/lib/models/extra_action.dart b/bloc_library/lib/models/extra_action.dart index 236a7d0b..4ca0c02b 100644 --- a/bloc_library/lib/models/extra_action.dart +++ b/bloc_library/lib/models/extra_action.dart @@ -1,5 +1 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - enum ExtraAction { toggleAllComplete, clearCompleted } diff --git a/bloc_library/lib/models/models.dart b/bloc_library/lib/models/models.dart index 21dff725..69216858 100644 --- a/bloc_library/lib/models/models.dart +++ b/bloc_library/lib/models/models.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - export 'app_tab.dart'; export 'extra_action.dart'; export 'todo.dart'; diff --git a/bloc_library/lib/models/todo.dart b/bloc_library/lib/models/todo.dart index 025120dc..ccdf3cbd 100644 --- a/bloc_library/lib/models/todo.dart +++ b/bloc_library/lib/models/todo.dart @@ -1,9 +1,5 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:todos_app_core/todos_app_core.dart'; import 'package:meta/meta.dart'; +import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @immutable @@ -13,11 +9,10 @@ class Todo { final String note; final String task; - Todo(this.task, {this.complete = false, String note = '', String id}) - : note = note ?? '', - id = id ?? Uuid().generateV4(); + Todo(this.task, {this.complete = false, this.note = '', String? id}) + : id = id ?? Uuid().generateV4(); - Todo copyWith({bool complete, String id, String note, String task}) { + Todo copyWith({bool? complete, String? id, String? note, String? task}) { return Todo( task ?? this.task, complete: complete ?? this.complete, @@ -52,9 +47,9 @@ class Todo { static Todo fromEntity(TodoEntity entity) { return Todo( entity.task, - complete: entity.complete ?? false, + complete: entity.complete, note: entity.note, - id: entity.id ?? Uuid().generateV4(), + id: entity.id, ); } } diff --git a/bloc_library/lib/models/visibility_filter.dart b/bloc_library/lib/models/visibility_filter.dart index 11f11982..a47beca1 100644 --- a/bloc_library/lib/models/visibility_filter.dart +++ b/bloc_library/lib/models/visibility_filter.dart @@ -1,5 +1 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - enum VisibilityFilter { all, active, completed } diff --git a/bloc_library/lib/run_app.dart b/bloc_library/lib/run_app.dart deleted file mode 100644 index c4a6dad4..00000000 --- a/bloc_library/lib/run_app.dart +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:bloc/bloc.dart'; -import 'package:bloc_library/blocs/blocs.dart'; -import 'package:bloc_library/localization.dart'; -import 'package:bloc_library/models/models.dart'; -import 'package:bloc_library/screens/screens.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -void runBlocLibraryApp(TodosRepository repository) { - // BlocSupervisor oversees Blocs and delegates to BlocDelegate. - // We can set the BlocSupervisor's delegate to an instance of `SimpleBlocDelegate`. - // This will allow us to handle all transitions and errors in SimpleBlocDelegate. - BlocSupervisor.delegate = SimpleBlocDelegate(); - runApp( - BlocProvider( - create: (context) { - return TodosBloc(todosRepository: repository)..add(LoadTodos()); - }, - child: TodosApp(), - ), - ); -} - -class TodosApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - final todosBloc = BlocProvider.of(context); - - return MaterialApp( - onGenerateTitle: (context) => - FlutterBlocLocalizations.of(context).appTitle, - theme: ArchSampleTheme.theme, - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - FlutterBlocLocalizationsDelegate(), - ], - routes: { - ArchSampleRoutes.home: (context) { - return MultiBlocProvider( - providers: [ - BlocProvider( - create: (context) => TabBloc(), - ), - BlocProvider( - create: (context) => FilteredTodosBloc(todosBloc: todosBloc), - ), - BlocProvider( - create: (context) => StatsBloc(todosBloc: todosBloc), - ), - ], - child: HomeScreen(), - ); - }, - ArchSampleRoutes.addTodo: (context) { - return AddEditScreen( - key: ArchSampleKeys.addTodoScreen, - onSave: (task, note) { - todosBloc.add(AddTodo(Todo(task, note: note))); - }, - isEditing: false, - ); - }, - }, - ); - } -} diff --git a/bloc_library/lib/screens/add_edit_screen.dart b/bloc_library/lib/screens/add_edit_screen.dart index 8c67e96a..3ac58e90 100644 --- a/bloc_library/lib/screens/add_edit_screen.dart +++ b/bloc_library/lib/screens/add_edit_screen.dart @@ -1,35 +1,30 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; +import 'package:bloc_library/models/models.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:bloc_library/models/models.dart'; typedef OnSaveCallback = void Function(String task, String note); class AddEditScreen extends StatefulWidget { final bool isEditing; final OnSaveCallback onSave; - final Todo todo; + final Todo? todo; - AddEditScreen({ - Key key, - @required this.onSave, - @required this.isEditing, + const AddEditScreen({ + super.key = ArchSampleKeys.addTodoScreen, + required this.onSave, + required this.isEditing, this.todo, - }) : super(key: key ?? ArchSampleKeys.addTodoScreen); + }); @override - _AddEditScreenState createState() => _AddEditScreenState(); + AddEditScreenState createState() => AddEditScreenState(); } -class _AddEditScreenState extends State { +class AddEditScreenState extends State { static final GlobalKey _formKey = GlobalKey(); - String _task; - String _note; + late String _task; + late String _note; bool get isEditing => widget.isEditing; @@ -40,9 +35,7 @@ class _AddEditScreenState extends State { return Scaffold( appBar: AppBar( - title: Text( - isEditing ? localizations.editTodo : localizations.addTodo, - ), + title: Text(isEditing ? localizations.editTodo : localizations.addTodo), ), body: Padding( padding: EdgeInsets.all(16.0), @@ -51,42 +44,41 @@ class _AddEditScreenState extends State { child: ListView( children: [ TextFormField( - initialValue: isEditing ? widget.todo.task : '', + initialValue: isEditing ? widget.todo!.task : '', key: ArchSampleKeys.taskField, autofocus: !isEditing, - style: textTheme.headline, + style: textTheme.titleLarge, decoration: InputDecoration( hintText: localizations.newTodoHint, ), validator: (val) { - return val.trim().isEmpty + return val != null && val.trim().isEmpty ? localizations.emptyTodoError : null; }, - onSaved: (value) => _task = value, + onSaved: (value) => _task = value ?? '', ), TextFormField( - initialValue: isEditing ? widget.todo.note : '', + initialValue: isEditing ? widget.todo!.note : '', key: ArchSampleKeys.noteField, maxLines: 10, - style: textTheme.subhead, - decoration: InputDecoration( - hintText: localizations.notesHint, - ), - onSaved: (value) => _note = value, - ) + style: textTheme.titleMedium, + decoration: InputDecoration(hintText: localizations.notesHint), + onSaved: (value) => _note = value ?? '', + ), ], ), ), ), floatingActionButton: FloatingActionButton( - key: - isEditing ? ArchSampleKeys.saveTodoFab : ArchSampleKeys.saveNewTodo, + key: isEditing + ? ArchSampleKeys.saveTodoFab + : ArchSampleKeys.saveNewTodo, tooltip: isEditing ? localizations.saveChanges : localizations.addTodo, child: Icon(isEditing ? Icons.check : Icons.add), onPressed: () { - if (_formKey.currentState.validate()) { - _formKey.currentState.save(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); widget.onSave(_task, _note); Navigator.pop(context); } diff --git a/bloc_library/lib/screens/details_screen.dart b/bloc_library/lib/screens/details_screen.dart index 701f409d..34d3bfe7 100644 --- a/bloc_library/lib/screens/details_screen.dart +++ b/bloc_library/lib/screens/details_screen.dart @@ -1,20 +1,18 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; +import 'package:bloc_library/bloc_library_keys.dart'; +import 'package:bloc_library/blocs/todos/todos.dart'; +import 'package:bloc_library/screens/screens.dart'; +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:bloc_library/blocs/todos/todos.dart'; -import 'package:bloc_library/screens/screens.dart'; -import 'package:bloc_library/bloc_library_keys.dart'; class DetailsScreen extends StatelessWidget { final String id; - DetailsScreen({Key key, @required this.id}) - : super(key: key ?? ArchSampleKeys.todoDetailsScreen); + const DetailsScreen({ + super.key = ArchSampleKeys.todoDetailsScreen, + required this.id, + }); @override Widget build(BuildContext context) { @@ -22,9 +20,9 @@ class DetailsScreen extends StatelessWidget { return BlocBuilder( bloc: todosBloc, builder: (BuildContext context, TodosState state) { - final todo = (state as TodosLoaded) - .todos - .firstWhere((todo) => todo.id == id, orElse: () => null); + final todo = (state as TodosLoaded).todos.firstWhereOrNull( + (todo) => todo.id == id, + ); final localizations = ArchSampleLocalizations.of(context); return Scaffold( appBar: AppBar( @@ -35,10 +33,10 @@ class DetailsScreen extends StatelessWidget { key: ArchSampleKeys.deleteTodoButton, icon: Icon(Icons.delete), onPressed: () { - todosBloc.add(DeleteTodo(todo)); + todosBloc.add(DeleteTodo(todo!)); Navigator.pop(context, todo); }, - ) + ), ], ), body: todo == null @@ -53,15 +51,16 @@ class DetailsScreen extends StatelessWidget { Padding( padding: EdgeInsets.only(right: 8.0), child: Checkbox( - key: BlocLibraryKeys.detailsScreenCheckBox, - value: todo.complete, - onChanged: (_) { - todosBloc.add( - UpdateTodo( - todo.copyWith(complete: !todo.complete), - ), - ); - }), + key: BlocLibraryKeys.detailsScreenCheckBox, + value: todo.complete, + onChanged: (_) { + todosBloc.add( + UpdateTodo( + todo.copyWith(complete: !todo.complete), + ), + ); + }, + ), ), Expanded( child: Column( @@ -78,15 +77,18 @@ class DetailsScreen extends StatelessWidget { child: Text( todo.task, key: ArchSampleKeys.detailsTodoItemTask, - style: - Theme.of(context).textTheme.headline, + style: Theme.of( + context, + ).textTheme.headlineSmall, ), ), ), Text( todo.note, key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, + style: Theme.of( + context, + ).textTheme.titleMedium, ), ], ), @@ -99,7 +101,6 @@ class DetailsScreen extends StatelessWidget { floatingActionButton: FloatingActionButton( key: ArchSampleKeys.editTodoFab, tooltip: localizations.editTodo, - child: Icon(Icons.edit), onPressed: todo == null ? null : () { @@ -122,6 +123,7 @@ class DetailsScreen extends StatelessWidget { ), ); }, + child: Icon(Icons.edit), ), ); }, diff --git a/bloc_library/lib/screens/home_screen.dart b/bloc_library/lib/screens/home_screen.dart index 043e001e..2d7daca3 100644 --- a/bloc_library/lib/screens/home_screen.dart +++ b/bloc_library/lib/screens/home_screen.dart @@ -1,17 +1,15 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:bloc_library/blocs/blocs.dart'; -import 'package:bloc_library/widgets/widgets.dart'; +import 'package:bloc_library/blocs/tab/tab.dart'; import 'package:bloc_library/localization.dart'; import 'package:bloc_library/models/models.dart'; -import 'package:bloc_library/blocs/tab/tab.dart'; +import 'package:bloc_library/widgets/widgets.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class HomeScreen extends StatelessWidget { + const HomeScreen({super.key}); + @override Widget build(BuildContext context) { final tabBloc = BlocProvider.of(context); @@ -31,8 +29,8 @@ class HomeScreen extends StatelessWidget { onPressed: () { Navigator.pushNamed(context, ArchSampleRoutes.addTodo); }, - child: Icon(Icons.add), tooltip: ArchSampleLocalizations.of(context).addTodo, + child: Icon(Icons.add), ), bottomNavigationBar: TabSelector( activeTab: activeTab, diff --git a/bloc_library/lib/widgets/delete_todo_snack_bar.dart b/bloc_library/lib/widgets/delete_todo_snack_bar.dart index d9df69ab..cbd115e9 100644 --- a/bloc_library/lib/widgets/delete_todo_snack_bar.dart +++ b/bloc_library/lib/widgets/delete_todo_snack_bar.dart @@ -1,26 +1,22 @@ +import 'package:bloc_library/models/models.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:bloc_library/models/models.dart'; class DeleteTodoSnackBar extends SnackBar { final ArchSampleLocalizations localizations; DeleteTodoSnackBar({ - Key key, - @required Todo todo, - @required VoidCallback onUndo, - @required this.localizations, + super.key, + required Todo todo, + required VoidCallback onUndo, + required this.localizations, + super.duration = const Duration(seconds: 2), }) : super( - key: key, - content: Text( - localizations.todoDeleted(todo.task), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - duration: Duration(seconds: 2), - action: SnackBarAction( - label: localizations.undo, - onPressed: onUndo, - ), - ); + content: Text( + localizations.todoDeleted(todo.task), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + action: SnackBarAction(label: localizations.undo, onPressed: onUndo), + ); } diff --git a/bloc_library/lib/widgets/extra_actions.dart b/bloc_library/lib/widgets/extra_actions.dart index cb9992d8..1e5c71ce 100644 --- a/bloc_library/lib/widgets/extra_actions.dart +++ b/bloc_library/lib/widgets/extra_actions.dart @@ -1,18 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:bloc_library/bloc_library_keys.dart'; +import 'package:bloc_library/blocs/todos/todos.dart'; +import 'package:bloc_library/models/models.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:bloc_library/blocs/todos/todos.dart'; -import 'package:bloc_library/models/models.dart'; -import 'package:bloc_library/bloc_library_keys.dart'; class ExtraActions extends StatelessWidget { - ExtraActions({Key key}) : super(key: ArchSampleKeys.extraActionsButton); + const ExtraActions({super.key = ArchSampleKeys.extraActionsButton}); @override Widget build(BuildContext context) { @@ -21,9 +15,9 @@ class ExtraActions extends StatelessWidget { bloc: todosBloc, builder: (BuildContext context, TodosState state) { if (state is TodosLoaded) { - final allComplete = (todosBloc.state as TodosLoaded) - .todos - .every((todo) => todo.complete); + final allComplete = (todosBloc.state as TodosLoaded).todos.every( + (todo) => todo.complete, + ); return PopupMenuButton( key: BlocLibraryKeys.extraActionsPopupMenuButton, onSelected: (action) { @@ -49,9 +43,7 @@ class ExtraActions extends StatelessWidget { PopupMenuItem( key: ArchSampleKeys.clearCompleted, value: ExtraAction.clearCompleted, - child: Text( - ArchSampleLocalizations.of(context).clearCompleted, - ), + child: Text(ArchSampleLocalizations.of(context).clearCompleted), ), ], ); diff --git a/bloc_library/lib/widgets/filter_button.dart b/bloc_library/lib/widgets/filter_button.dart index f81ace89..a17cdd34 100644 --- a/bloc_library/lib/widgets/filter_button.dart +++ b/bloc_library/lib/widgets/filter_button.dart @@ -1,56 +1,52 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:bloc_library/blocs/filtered_todos/filtered_todos.dart'; +import 'package:bloc_library/models/models.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:bloc_library/blocs/filtered_todos/filtered_todos.dart'; -import 'package:bloc_library/models/models.dart'; class FilterButton extends StatelessWidget { final bool visible; - FilterButton({this.visible, Key key}) : super(key: key); + const FilterButton({super.key, required this.visible}); @override Widget build(BuildContext context) { - final defaultStyle = Theme.of(context).textTheme.body1; - final activeStyle = Theme.of(context) - .textTheme - .body1 - .copyWith(color: Theme.of(context).accentColor); + final defaultStyle = Theme.of(context).textTheme.bodyMedium!; + final activeStyle = defaultStyle.copyWith( + color: Theme.of(context).colorScheme.secondary, + ); final filteredTodosBloc = BlocProvider.of(context); + return BlocBuilder( - bloc: filteredTodosBloc, - builder: (BuildContext context, FilteredTodosState state) { - final button = _Button( - onSelected: (filter) { - filteredTodosBloc.add(UpdateFilter(filter)); - }, - activeFilter: state is FilteredTodosLoaded - ? state.activeFilter - : VisibilityFilter.all, - activeStyle: activeStyle, - defaultStyle: defaultStyle, - ); - return AnimatedOpacity( - opacity: visible ? 1.0 : 0.0, - duration: Duration(milliseconds: 150), - child: visible ? button : IgnorePointer(child: button), - ); - }); + bloc: filteredTodosBloc, + builder: (BuildContext context, FilteredTodosState state) { + final button = _Button( + onSelected: (filter) { + filteredTodosBloc.add(UpdateFilter(filter)); + }, + activeFilter: state is FilteredTodosLoaded + ? state.activeFilter + : VisibilityFilter.all, + activeStyle: activeStyle, + defaultStyle: defaultStyle, + ); + return AnimatedOpacity( + opacity: visible ? 1.0 : 0.0, + duration: Duration(milliseconds: 150), + child: visible ? button : IgnorePointer(child: button), + ); + }, + ); } } class _Button extends StatelessWidget { const _Button({ - Key key, - @required this.onSelected, - @required this.activeFilter, - @required this.activeStyle, - @required this.defaultStyle, - }) : super(key: key); + required this.onSelected, + required this.activeFilter, + required this.activeStyle, + required this.defaultStyle, + }); final PopupMenuItemSelected onSelected; final VisibilityFilter activeFilter; diff --git a/bloc_library/lib/widgets/filtered_todos.dart b/bloc_library/lib/widgets/filtered_todos.dart index e1c6f8d7..de6f85f2 100644 --- a/bloc_library/lib/widgets/filtered_todos.dart +++ b/bloc_library/lib/widgets/filtered_todos.dart @@ -1,20 +1,14 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:bloc_library/bloc_library_keys.dart'; +import 'package:bloc_library/blocs/blocs.dart'; import 'package:bloc_library/models/models.dart'; +import 'package:bloc_library/screens/screens.dart'; +import 'package:bloc_library/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:bloc_library/blocs/blocs.dart'; -import 'package:bloc_library/widgets/widgets.dart'; -import 'package:bloc_library/screens/screens.dart'; -import 'package:bloc_library/bloc_library_keys.dart'; class FilteredTodos extends StatelessWidget { - FilteredTodos({Key key}) : super(key: key); + const FilteredTodos({super.key}); @override Widget build(BuildContext context) { @@ -22,10 +16,7 @@ class FilteredTodos extends StatelessWidget { final localizations = ArchSampleLocalizations.of(context); return BlocBuilder( - builder: ( - BuildContext context, - FilteredTodosState state, - ) { + builder: (BuildContext context, FilteredTodosState state) { if (state is FilteredTodosLoading) { return LoadingIndicator(key: ArchSampleKeys.todosLoading); } else if (state is FilteredTodosLoaded) { @@ -39,26 +30,32 @@ class FilteredTodos extends StatelessWidget { todo: todo, onDismissed: (_) { todosBloc.add(DeleteTodo(todo)); - Scaffold.of(context).showSnackBar(DeleteTodoSnackBar( - key: ArchSampleKeys.snackbar, - todo: todo, - onUndo: () => todosBloc.add(AddTodo(todo)), - localizations: localizations, - )); - }, - onTap: () async { - final removedTodo = await Navigator.of(context).push( - MaterialPageRoute(builder: (_) { - return DetailsScreen(id: todo.id); - }), - ); - if (removedTodo != null) { - Scaffold.of(context).showSnackBar(DeleteTodoSnackBar( + ScaffoldMessenger.of(context).showSnackBar( + DeleteTodoSnackBar( key: ArchSampleKeys.snackbar, todo: todo, onUndo: () => todosBloc.add(AddTodo(todo)), localizations: localizations, - )); + ), + ); + }, + onTap: () async { + final removedTodo = await Navigator.of(context).push( + MaterialPageRoute( + builder: (_) { + return DetailsScreen(id: todo.id); + }, + ), + ); + if (removedTodo != null && context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + DeleteTodoSnackBar( + key: ArchSampleKeys.snackbar, + todo: todo, + onUndo: () => todosBloc.add(AddTodo(todo)), + localizations: localizations, + ), + ); } }, onCheckboxChanged: (_) { diff --git a/bloc_library/lib/widgets/loading_indicator.dart b/bloc_library/lib/widgets/loading_indicator.dart index 822a4c32..d8023b90 100644 --- a/bloc_library/lib/widgets/loading_indicator.dart +++ b/bloc_library/lib/widgets/loading_indicator.dart @@ -1,16 +1,10 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; class LoadingIndicator extends StatelessWidget { - LoadingIndicator({Key key}) : super(key: key); + const LoadingIndicator({super.key}); @override Widget build(BuildContext context) { - return Center( - child: CircularProgressIndicator(), - ); + return Center(child: CircularProgressIndicator()); } } diff --git a/bloc_library/lib/widgets/stats.dart b/bloc_library/lib/widgets/stats.dart index 59b6940d..b9e3e2e5 100644 --- a/bloc_library/lib/widgets/stats.dart +++ b/bloc_library/lib/widgets/stats.dart @@ -1,18 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:bloc_library/bloc_library_keys.dart'; +import 'package:bloc_library/blocs/stats/stats.dart'; +import 'package:bloc_library/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:bloc_library/blocs/stats/stats.dart'; -import 'package:bloc_library/widgets/widgets.dart'; -import 'package:bloc_library/bloc_library_keys.dart'; class Stats extends StatelessWidget { - Stats({Key key}) : super(key: key); + const Stats({super.key}); @override Widget build(BuildContext context) { @@ -31,7 +25,7 @@ class Stats extends StatelessWidget { padding: EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -39,14 +33,14 @@ class Stats extends StatelessWidget { child: Text( '${state.numCompleted}', key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), Padding( padding: EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -54,9 +48,9 @@ class Stats extends StatelessWidget { child: Text( '${state.numActive}', key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), - ) + ), ], ), ); diff --git a/bloc_library/lib/widgets/tab_selector.dart b/bloc_library/lib/widgets/tab_selector.dart index 4fd51b4e..e6911319 100644 --- a/bloc_library/lib/widgets/tab_selector.dart +++ b/bloc_library/lib/widgets/tab_selector.dart @@ -1,22 +1,16 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; +import 'package:bloc_library/models/models.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:bloc_library/models/models.dart'; class TabSelector extends StatelessWidget { final AppTab activeTab; - final Function(AppTab) onTabSelected; + final void Function(AppTab) onTabSelected; - TabSelector({ - Key key, - @required this.activeTab, - @required this.onTabSelected, - }) : super(key: key); + const TabSelector({ + super.key, + required this.activeTab, + required this.onTabSelected, + }); @override Widget build(BuildContext context) { @@ -32,9 +26,9 @@ class TabSelector extends StatelessWidget { ? ArchSampleKeys.todoTab : ArchSampleKeys.statsTab, ), - title: Text(tab == AppTab.stats + label: tab == AppTab.stats ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos), + : ArchSampleLocalizations.of(context).todos, ); }).toList(), ); diff --git a/bloc_library/lib/widgets/todo_item.dart b/bloc_library/lib/widgets/todo_item.dart index 8f7c8e0f..0a9fc79d 100644 --- a/bloc_library/lib/widgets/todo_item.dart +++ b/bloc_library/lib/widgets/todo_item.dart @@ -1,26 +1,20 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; +import 'package:bloc_library/models/models.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:bloc_library/models/models.dart'; class TodoItem extends StatelessWidget { final DismissDirectionCallback onDismissed; final GestureTapCallback onTap; - final ValueChanged onCheckboxChanged; + final ValueChanged onCheckboxChanged; final Todo todo; - TodoItem({ - Key key, - @required this.onDismissed, - @required this.onTap, - @required this.onCheckboxChanged, - @required this.todo, - }) : super(key: key); + const TodoItem({ + super.key, + required this.onDismissed, + required this.onTap, + required this.onCheckboxChanged, + required this.todo, + }); @override Widget build(BuildContext context) { @@ -36,12 +30,12 @@ class TodoItem extends StatelessWidget { ), title: Hero( tag: '${todo.id}__heroTag', - child: Container( + child: SizedBox( width: MediaQuery.of(context).size.width, child: Text( todo.task, key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), ), @@ -51,7 +45,7 @@ class TodoItem extends StatelessWidget { key: ArchSampleKeys.todoItemNote(todo.id), maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ) : null, ), diff --git a/bloc_library/linux/.gitignore b/bloc_library/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/bloc_library/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/bloc_library/linux/CMakeLists.txt b/bloc_library/linux/CMakeLists.txt new file mode 100644 index 00000000..440e1050 --- /dev/null +++ b/bloc_library/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +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 "bloc_library") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.bloc_library") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +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() + +# 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() + +# 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_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# 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 +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# 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() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +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) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/bloc_library/linux/flutter/CMakeLists.txt b/bloc_library/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/bloc_library/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +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. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# 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/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter 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. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/bloc_library/linux/flutter/generated_plugin_registrant.cc b/bloc_library/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e71a16d2 --- /dev/null +++ b/bloc_library/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/bloc_library/linux/flutter/generated_plugin_registrant.h b/bloc_library/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/bloc_library/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/bloc_library/linux/flutter/generated_plugins.cmake b/bloc_library/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/bloc_library/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + 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}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/bloc_library/linux/runner/CMakeLists.txt b/bloc_library/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/bloc_library/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "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 +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/bloc_library/linux/runner/main.cc b/bloc_library/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/bloc_library/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/bloc_library/linux/runner/my_application.cc b/bloc_library/linux/runner/my_application.cc new file mode 100644 index 00000000..96ce90c6 --- /dev/null +++ b/bloc_library/linux/runner/my_application.cc @@ -0,0 +1,144 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView *view) +{ + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // 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 + // desktop). + // 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. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "bloc_library"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "bloc_library"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/bloc_library/linux/runner/my_application.h b/bloc_library/linux/runner/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/bloc_library/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/bloc_library/macos/.gitignore b/bloc_library/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/bloc_library/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/bloc_library/macos/Flutter/Flutter-Debug.xcconfig b/bloc_library/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/bloc_library/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/bloc_library/macos/Flutter/Flutter-Release.xcconfig b/bloc_library/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/bloc_library/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/bloc_library/macos/Flutter/GeneratedPluginRegistrant.swift b/bloc_library/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b8e2b22f --- /dev/null +++ b/bloc_library/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/bloc_library/macos/Podfile b/bloc_library/macos/Podfile new file mode 100644 index 00000000..ff5ddb3b --- /dev/null +++ b/bloc_library/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/bloc_library/macos/Runner.xcodeproj/project.pbxproj b/bloc_library/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..1cffa9d3 --- /dev/null +++ b/bloc_library/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 05215CB3952DD67831212113 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD41C94EFB350DBBC107BADF /* Pods_RunnerTests.framework */; }; + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + C17BDF907BEBFB467BF93B42 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D39C3C8521738CE7D83AB14 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0D39C3C8521738CE7D83AB14 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 267266BF2CAA380167CEF097 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 27E7DA4E6426CAD5A0AF7319 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* bloc_library.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = bloc_library.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7844CE7CE7412234E982BEEB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + CD41C94EFB350DBBC107BADF /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D56BC89C1DB51627880262D1 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + DC11667C436BEAB4299BFD9F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + E397FEC6F60680734CEF843E /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 05215CB3952DD67831212113 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C17BDF907BEBFB467BF93B42 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 6C91901967C03EDB3F7084EA /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* bloc_library.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 6C91901967C03EDB3F7084EA /* Pods */ = { + isa = PBXGroup; + children = ( + DC11667C436BEAB4299BFD9F /* Pods-Runner.debug.xcconfig */, + 27E7DA4E6426CAD5A0AF7319 /* Pods-Runner.release.xcconfig */, + 7844CE7CE7412234E982BEEB /* Pods-Runner.profile.xcconfig */, + D56BC89C1DB51627880262D1 /* Pods-RunnerTests.debug.xcconfig */, + 267266BF2CAA380167CEF097 /* Pods-RunnerTests.release.xcconfig */, + E397FEC6F60680734CEF843E /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 0D39C3C8521738CE7D83AB14 /* Pods_Runner.framework */, + CD41C94EFB350DBBC107BADF /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 833DE8611462CBE2D0807EE6 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 7468B20854C62193CF81A82C /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + C370B145C35582820C571194 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* bloc_library.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 7468B20854C62193CF81A82C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 833DE8611462CBE2D0807EE6 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C370B145C35582820C571194 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D56BC89C1DB51627880262D1 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.blocLibrary.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bloc_library.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bloc_library"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 267266BF2CAA380167CEF097 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.blocLibrary.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bloc_library.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bloc_library"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E397FEC6F60680734CEF843E /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.blocLibrary.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bloc_library.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bloc_library"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/bloc_library/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/bloc_library/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/bloc_library/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/bloc_library/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/bloc_library/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..cb5149a8 --- /dev/null +++ b/bloc_library/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/firestore_redux/ios/Runner.xcworkspace/contents.xcworkspacedata b/bloc_library/macos/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from firestore_redux/ios/Runner.xcworkspace/contents.xcworkspacedata rename to bloc_library/macos/Runner.xcworkspace/contents.xcworkspacedata diff --git a/bloc_library/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/bloc_library/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/bloc_library/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/bloc_library/macos/Runner/AppDelegate.swift b/bloc_library/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/bloc_library/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/bloc_library/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/bloc_library/macos/Runner/Base.lproj/MainMenu.xib b/bloc_library/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/bloc_library/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bloc_library/macos/Runner/Configs/AppInfo.xcconfig b/bloc_library/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..5f2b3c75 --- /dev/null +++ b/bloc_library/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// 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 +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = bloc_library + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.blocLibrary + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/bloc_library/macos/Runner/Configs/Debug.xcconfig b/bloc_library/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/bloc_library/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/bloc_library/macos/Runner/Configs/Release.xcconfig b/bloc_library/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/bloc_library/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/bloc_library/macos/Runner/Configs/Warnings.xcconfig b/bloc_library/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/bloc_library/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/bloc_library/macos/Runner/DebugProfile.entitlements b/bloc_library/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/bloc_library/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/bloc_library/macos/Runner/Info.plist b/bloc_library/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/bloc_library/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/bloc_library/macos/Runner/MainFlutterWindow.swift b/bloc_library/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/bloc_library/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/bloc_library/macos/Runner/Release.entitlements b/bloc_library/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/bloc_library/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/bloc_library/macos/RunnerTests/RunnerTests.swift b/bloc_library/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/bloc_library/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/bloc_library/pubspec.yaml b/bloc_library/pubspec.yaml index 878d0848..e2813b85 100644 --- a/bloc_library/pubspec.yaml +++ b/bloc_library/pubspec.yaml @@ -12,11 +12,14 @@ description: A new Flutter project. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html version: 1.0.0+1 +publish_to: "none" environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ^3.9.0 dependencies: + bloc: + collection: flutter: sdk: flutter todos_app_core: @@ -25,31 +28,28 @@ dependencies: path: ../todos_repository_local_storage todos_repository_core: path: ../todos_repository_core - meta: ">=1.1.0 <2.0.0" - equatable: ^1.0.2 - flutter_bloc: ^3.1.0 - key_value_store_flutter: - key_value_store_web: + meta: + equatable: + flutter_bloc: shared_preferences: dev_dependencies: + bloc_test: + flutter_lints: flutter_test: sdk: flutter - flutter_driver: + integration_test: sdk: flutter - test: - mockito: - bloc_test: ^3.0.1 integration_tests: path: ../integration_tests - + mocktail: + test: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. diff --git a/bloc_library/test/all_tests.dart b/bloc_library/test/all_tests.dart index 07be21c9..d51c2a2c 100644 --- a/bloc_library/test/all_tests.dart +++ b/bloc_library/test/all_tests.dart @@ -4,7 +4,7 @@ import './blocs/filtered_todos_bloc_test.dart' as filtered_todos_bloc; import './blocs/filtered_todos_event_test.dart' as filtered_todos_event; -import './blocs/simple_bloc_delegate_test.dart' as simple_bloc_delegate; +import 'blocs/simple_bloc_observer_test.dart' as simple_bloc_delegate; import './blocs/tab_bloc_test.dart' as tab_bloc; import './blocs/tab_event_test.dart' as tab_event; import './blocs/todos_bloc_test.dart' as todos_bloc; diff --git a/bloc_library/test/blocs/filtered_todos_bloc_test.dart b/bloc_library/test/blocs/filtered_todos_bloc_test.dart index 42f44d78..d06c2d4c 100644 --- a/bloc_library/test/blocs/filtered_todos_bloc_test.dart +++ b/bloc_library/test/blocs/filtered_todos_bloc_test.dart @@ -1,13 +1,10 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; -import 'package:bloc_test/bloc_test.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; + import 'package:bloc_library/blocs/blocs.dart'; import 'package:bloc_library/models/models.dart'; +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; class MockTodosBloc extends MockBloc @@ -16,14 +13,14 @@ class MockTodosBloc extends MockBloc class MockTodosRepository extends Mock implements LocalStorageRepository {} void main() { - group('FilteredTodosBloc', () { - blocTest( + group('$FilteredTodosBloc', () { + blocTest( 'adds TodosUpdated when TodosBloc.state emits TodosLoaded', build: () { final todosBloc = MockTodosBloc(); - when(todosBloc.state).thenReturn( - TodosLoaded([Todo('Wash Dishes', id: '0')]), - ); + when( + () => todosBloc.state, + ).thenReturn(TodosLoaded([Todo('Wash Dishes', id: '0')])); whenListen( todosBloc, Stream.fromIterable([ @@ -32,53 +29,43 @@ void main() { ); return FilteredTodosBloc(todosBloc: todosBloc); }, - expect: [ - FilteredTodosLoaded( - [Todo('Wash Dishes', id: '0')], - VisibilityFilter.all, - ), + expect: () => [ + FilteredTodosLoaded([ + Todo('Wash Dishes', id: '0'), + ], VisibilityFilter.all), ], ); - blocTest( + blocTest( 'should update the VisibilityFilter when filter is active', build: () { final todosBloc = MockTodosBloc(); - when(todosBloc.state) - .thenReturn(TodosLoaded([Todo('Wash Dishes', id: '0')])); + when( + () => todosBloc.state, + ).thenReturn(TodosLoaded([Todo('Wash Dishes', id: '0')])); return FilteredTodosBloc(todosBloc: todosBloc); }, act: (FilteredTodosBloc bloc) async => bloc.add(UpdateFilter(VisibilityFilter.active)), - expect: [ - FilteredTodosLoaded( - [Todo('Wash Dishes', id: '0')], - VisibilityFilter.all, - ), - FilteredTodosLoaded( - [Todo('Wash Dishes', id: '0')], - VisibilityFilter.active, - ), + expect: () => [ + FilteredTodosLoaded([ + Todo('Wash Dishes', id: '0'), + ], VisibilityFilter.active), ], ); - blocTest( + blocTest( 'should update the VisibilityFilter when filter is completed', build: () { final todosBloc = MockTodosBloc(); - when(todosBloc.state) - .thenReturn(TodosLoaded([Todo('Wash Dishes', id: '0')])); + when( + () => todosBloc.state, + ).thenReturn(TodosLoaded([Todo('Wash Dishes', id: '0')])); return FilteredTodosBloc(todosBloc: todosBloc); }, act: (FilteredTodosBloc bloc) async => bloc.add(UpdateFilter(VisibilityFilter.completed)), - expect: [ - FilteredTodosLoaded( - [Todo('Wash Dishes', id: '0')], - VisibilityFilter.all, - ), - FilteredTodosLoaded([], VisibilityFilter.completed), - ], + expect: () => [FilteredTodosLoaded([], VisibilityFilter.completed)], ); }); } diff --git a/bloc_library/test/blocs/filtered_todos_event_test.dart b/bloc_library/test/blocs/filtered_todos_event_test.dart index 0fcfc72c..1dc61d75 100644 --- a/bloc_library/test/blocs/filtered_todos_event_test.dart +++ b/bloc_library/test/blocs/filtered_todos_event_test.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter_test/flutter_test.dart'; import 'package:bloc_library/blocs/blocs.dart'; import 'package:bloc_library/models/models.dart'; diff --git a/bloc_library/test/blocs/simple_bloc_delegate_test.dart b/bloc_library/test/blocs/simple_bloc_delegate_test.dart deleted file mode 100644 index 3a248422..00000000 --- a/bloc_library/test/blocs/simple_bloc_delegate_test.dart +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter_test/flutter_test.dart'; -import 'package:bloc_library/blocs/simple_bloc_delegate.dart'; -import 'package:bloc/bloc.dart'; -import 'dart:async'; - -List printLog; - -void main() { - group('SimpleBlocDelegate', () { - SimpleBlocDelegate delegate; - - setUp(() { - delegate = SimpleBlocDelegate(); - printLog = []; - }); - - test('onTransition prints Transition', overridePrint(() { - delegate.onTransition( - null, - Transition( - currentState: 'A', - event: 'E', - nextState: 'B', - ), - ); - expect( - printLog[0], - 'Transition { currentState: A, event: E, nextState: B }', - ); - })); - - test('onError prints Error', overridePrint(() { - delegate.onError(null, 'whoops', null); - expect( - printLog[0], - 'whoops', - ); - })); - - test('onEvent prints Event', overridePrint(() { - delegate.onEvent(null, 'event'); - expect( - printLog[0], - 'event', - ); - })); - }); -} - -dynamic overridePrint(dynamic Function() testFn) => () { - var spec = ZoneSpecification(print: (_, __, ___, String msg) { - // Add to log instead of printing to stdout - printLog.add(msg); - }); - return Zone.current.fork(specification: spec).run(testFn); - }; diff --git a/bloc_library/test/blocs/simple_bloc_observer_test.dart b/bloc_library/test/blocs/simple_bloc_observer_test.dart new file mode 100644 index 00000000..e0c24b37 --- /dev/null +++ b/bloc_library/test/blocs/simple_bloc_observer_test.dart @@ -0,0 +1,65 @@ +import 'dart:async'; + +import 'package:bloc/bloc.dart'; +import 'package:bloc_library/blocs/simple_bloc_observer.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class MockBloc extends Mock implements Bloc {} + +var printLog = []; + +void main() { + group('$SimpleBlocObserver', () { + late SimpleBlocObserver delegate; + + setUp(() { + delegate = SimpleBlocObserver(); + printLog = []; + }); + + test( + 'onTransition prints Transition', + overridePrint(() { + delegate.onTransition( + MockBloc(), + Transition( + currentState: 'A', + event: 'E', + nextState: 'B', + ), + ); + expect( + printLog[0], + 'Transition { currentState: A, event: E, nextState: B }', + ); + }), + ); + + test( + 'onError prints Error', + overridePrint(() { + delegate.onError(MockBloc(), 'whoops', StackTrace.empty); + expect(printLog[0], 'whoops'); + }), + ); + + test( + 'onEvent prints Event', + overridePrint(() { + delegate.onEvent(MockBloc(), 'event'); + expect(printLog[0], 'event'); + }), + ); + }); +} + +dynamic Function() overridePrint(void Function() testFn) => () { + var spec = ZoneSpecification( + print: (_, _, _, String msg) { + // Add to log instead of printing to stdout + printLog.add(msg); + }, + ); + return Zone.current.fork(specification: spec).run(testFn); +}; diff --git a/bloc_library/test/blocs/stats_bloc_test.dart b/bloc_library/test/blocs/stats_bloc_test.dart index 87a985a0..e828d4cd 100644 --- a/bloc_library/test/blocs/stats_bloc_test.dart +++ b/bloc_library/test/blocs/stats_bloc_test.dart @@ -1,14 +1,11 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; -import 'package:bloc_test/bloc_test.dart'; -import 'package:flutter_test/flutter_test.dart'; import 'package:bloc_library/blocs/stats/stats.dart'; import 'package:bloc_library/blocs/todos/todos.dart'; import 'package:bloc_library/models/models.dart'; +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; class MockTodosBloc extends MockBloc implements TodosBloc {} @@ -17,59 +14,52 @@ void main() { group('StatsBloc', () { final todo1 = Todo('Hallo'); final todo2 = Todo('Hallo2', complete: true); - TodosBloc todosBloc; - StatsBloc statsBloc; - - setUp(() { - todosBloc = MockTodosBloc(); - statsBloc = StatsBloc(todosBloc: todosBloc); - }); - blocTest( + blocTest( 'should update the stats properly when TodosBloc emits TodosLoaded', build: () { - todosBloc = MockTodosBloc(); + final todosBloc = MockTodosBloc(); + when(() => todosBloc.state).thenReturn(TodosLoading()); whenListen( todosBloc, Stream.fromIterable([TodosLoaded([])]), ); return StatsBloc(todosBloc: todosBloc); }, - act: (StatsBloc bloc) async => bloc.add(UpdateStats([])), - expect: [ - StatsLoading(), - StatsLoaded(0, 0), - ], + expect: () => [StatsLoaded(0, 0)], ); - blocTest( + blocTest( 'should update the stats properly when Todos are empty', - build: () => statsBloc, + build: () { + final todosBloc = MockTodosBloc(); + when(() => todosBloc.state).thenReturn(TodosLoading()); + return StatsBloc(todosBloc: todosBloc); + }, act: (StatsBloc bloc) async => bloc.add(UpdateStats([])), - expect: [ - StatsLoading(), - StatsLoaded(0, 0), - ], + expect: () => [StatsLoaded(0, 0)], ); - blocTest( + blocTest( 'should update the stats properly when Todos contains one active todo', - build: () => statsBloc, + build: () { + final todosBloc = MockTodosBloc(); + when(() => todosBloc.state).thenReturn(TodosLoading()); + return StatsBloc(todosBloc: todosBloc); + }, act: (StatsBloc bloc) async => bloc.add(UpdateStats([todo1])), - expect: [ - StatsLoading(), - StatsLoaded(1, 0), - ], + expect: () => [StatsLoaded(1, 0)], ); - blocTest( + blocTest( 'should update the stats properly when Todos contains one active todo and one completed todo', - build: () => statsBloc, + build: () { + final todosBloc = MockTodosBloc(); + when(() => todosBloc.state).thenReturn(TodosLoading()); + return StatsBloc(todosBloc: todosBloc); + }, act: (StatsBloc bloc) async => bloc.add(UpdateStats([todo1, todo2])), - expect: [ - StatsLoading(), - StatsLoaded(1, 1), - ], + expect: () => [StatsLoaded(1, 1)], ); }); } diff --git a/bloc_library/test/blocs/stats_event_test.dart b/bloc_library/test/blocs/stats_event_test.dart index f1ccf4a8..4c7ef0b0 100644 --- a/bloc_library/test/blocs/stats_event_test.dart +++ b/bloc_library/test/blocs/stats_event_test.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter_test/flutter_test.dart'; import 'package:bloc_library/blocs/blocs.dart'; @@ -9,10 +5,7 @@ void main() { group('StatsEvent', () { group('UpdateStats', () { test('toString returns correct value', () { - expect( - UpdateStats([]).toString(), - 'UpdateStats { todos: [] }', - ); + expect(UpdateStats([]).toString(), 'UpdateStats { todos: [] }'); }); }); }); diff --git a/bloc_library/test/blocs/tab_bloc_test.dart b/bloc_library/test/blocs/tab_bloc_test.dart index 47cf1cf0..89006460 100644 --- a/bloc_library/test/blocs/tab_bloc_test.dart +++ b/bloc_library/test/blocs/tab_bloc_test.dart @@ -1,22 +1,15 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:bloc_test/bloc_test.dart'; -import 'package:flutter_test/flutter_test.dart'; import 'package:bloc_library/blocs/tab/tab.dart'; import 'package:bloc_library/models/models.dart'; +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter_test/flutter_test.dart'; void main() { group('TabBloc', () { - blocTest( + blocTest( 'should update the AppTab', build: () => TabBloc(), act: (TabBloc bloc) async => bloc.add(UpdateTab(AppTab.stats)), - expect: [ - AppTab.todos, - AppTab.stats, - ], + expect: () => [AppTab.stats], ); }); } diff --git a/bloc_library/test/blocs/tab_event_test.dart b/bloc_library/test/blocs/tab_event_test.dart index 50b88fe5..032cf0db 100644 --- a/bloc_library/test/blocs/tab_event_test.dart +++ b/bloc_library/test/blocs/tab_event_test.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter_test/flutter_test.dart'; import 'package:bloc_library/blocs/blocs.dart'; import 'package:bloc_library/models/models.dart'; diff --git a/bloc_library/test/blocs/todos_bloc_test.dart b/bloc_library/test/blocs/todos_bloc_test.dart index fb9beaf4..fac3c122 100644 --- a/bloc_library/test/blocs/todos_bloc_test.dart +++ b/bloc_library/test/blocs/todos_bloc_test.dart @@ -1,71 +1,73 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:bloc_test/bloc_test.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; import 'package:bloc_library/blocs/todos/todos.dart'; import 'package:bloc_library/models/models.dart'; +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; class MockTodosRepository extends Mock implements LocalStorageRepository {} void main() { - group('TodosBloc', () { - LocalStorageRepository todosRepository; - TodosBloc todosBloc; + group('$TodosBloc', () { + late LocalStorageRepository todosRepository; + late TodosBloc todosBloc; setUp(() { todosRepository = MockTodosRepository(); - when(todosRepository.loadTodos()).thenAnswer((_) => Future.value([])); + when( + () => todosRepository.loadTodos(), + ).thenAnswer((_) => Future.value([])); + when( + () => todosRepository.saveTodos(any()), + ).thenAnswer((_) => Future.value()); todosBloc = TodosBloc(todosRepository: todosRepository); }); - blocTest( + blocTest( 'should emit TodosNotLoaded if repository throws', build: () { - when(todosRepository.loadTodos()).thenThrow(Exception('oops')); + when(() => todosRepository.loadTodos()).thenThrow(Exception('oops')); return todosBloc; }, act: (TodosBloc bloc) async => bloc.add(LoadTodos()), - expect: [ - TodosLoading(), - TodosNotLoaded(), - ], + expect: () => [TodosNotLoaded()], ); - blocTest( + blocTest( 'should add a todo to the list in response to an AddTodo Event', build: () => todosBloc, - act: (TodosBloc bloc) async => - bloc..add(LoadTodos())..add(AddTodo(Todo('Hallo', id: '0'))), - expect: [ - TodosLoading(), + act: (TodosBloc bloc) async => bloc + ..add(LoadTodos()) + ..add(AddTodo(Todo('Hallo', id: '0'))), + expect: () => [ TodosLoaded([]), TodosLoaded([Todo('Hallo', id: '0')]), ], ); - blocTest( + blocTest( 'should remove from the list in response to a DeleteTodo Event', build: () { - when(todosRepository.loadTodos()).thenAnswer((_) => Future.value([])); + when( + () => todosRepository.loadTodos(), + ).thenAnswer((_) => Future.value([])); return todosBloc; }, act: (TodosBloc bloc) async { final todo = Todo('Hallo', id: '0'); - bloc..add(LoadTodos())..add(AddTodo(todo))..add(DeleteTodo(todo)); + bloc + ..add(LoadTodos()) + ..add(AddTodo(todo)) + ..add(DeleteTodo(todo)); }, - expect: [ - TodosLoading(), + expect: () => [ TodosLoaded([]), TodosLoaded([Todo('Hallo', id: '0')]), TodosLoaded([]), ], ); - blocTest( + blocTest( 'should update a todo in response to an UpdateTodoAction', build: () => todosBloc, act: (TodosBloc bloc) async { @@ -75,15 +77,14 @@ void main() { ..add(AddTodo(todo)) ..add(UpdateTodo(todo.copyWith(task: 'Tschüss'))); }, - expect: [ - TodosLoading(), + expect: () => [ TodosLoaded([]), TodosLoaded([Todo('Hallo', id: '0')]), TodosLoaded([Todo('Tschüss', id: '0')]), ], ); - blocTest( + blocTest( 'should clear completed todos', build: () => todosBloc, act: (TodosBloc bloc) async { @@ -94,10 +95,8 @@ void main() { ..add(AddTodo(todo1)) ..add(AddTodo(todo2)) ..add(ClearCompleted()); - ; }, - expect: [ - TodosLoading(), + expect: () => [ TodosLoaded([]), TodosLoaded([Todo('Hallo', id: '0')]), TodosLoaded([ @@ -108,7 +107,7 @@ void main() { ], ); - blocTest( + blocTest( 'should mark all as completed if some todos are incomplete', build: () => todosBloc, act: (TodosBloc bloc) async { @@ -119,10 +118,8 @@ void main() { ..add(AddTodo(todo1)) ..add(AddTodo(todo2)) ..add(ToggleAll()); - ; }, - expect: [ - TodosLoading(), + expect: () => [ TodosLoaded([]), TodosLoaded([Todo('Hallo', id: '0')]), TodosLoaded([ @@ -136,7 +133,7 @@ void main() { ], ); - blocTest( + blocTest( 'should mark all as incomplete if all todos are complete', build: () => todosBloc, act: (TodosBloc bloc) async { @@ -147,20 +144,15 @@ void main() { ..add(AddTodo(todo1)) ..add(AddTodo(todo2)) ..add(ToggleAll()); - ; }, - expect: [ - TodosLoading(), + expect: () => [ TodosLoaded([]), TodosLoaded([Todo('Hallo', id: '0', complete: true)]), TodosLoaded([ Todo('Hallo', id: '0', complete: true), Todo('Tschüss', id: '1', complete: true), ]), - TodosLoaded([ - Todo('Hallo', id: '0'), - Todo('Tschüss', id: '1'), - ]), + TodosLoaded([Todo('Hallo', id: '0'), Todo('Tschüss', id: '1')]), ], ); }); diff --git a/bloc_library/test/blocs/todos_event_test.dart b/bloc_library/test/blocs/todos_event_test.dart index 6a478c15..3845773b 100644 --- a/bloc_library/test/blocs/todos_event_test.dart +++ b/bloc_library/test/blocs/todos_event_test.dart @@ -1,19 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter_test/flutter_test.dart'; import 'package:bloc_library/blocs/blocs.dart'; import 'package:bloc_library/models/models.dart'; +import 'package:flutter_test/flutter_test.dart'; void main() { group('TodosEvent', () { group('LoadTodos', () { test('toString returns correct value', () { - expect( - LoadTodos().toString(), - 'LoadTodos', - ); + expect(LoadTodos().toString(), 'LoadTodos()'); }); }); @@ -46,19 +39,13 @@ void main() { group('ClearCompleted', () { test('toString returns correct value', () { - expect( - ClearCompleted().toString(), - 'ClearCompleted', - ); + expect(ClearCompleted().toString(), 'ClearCompleted()'); }); }); group('ToggleAll', () { test('toString returns correct value', () { - expect( - ToggleAll().toString(), - 'ToggleAll', - ); + expect(ToggleAll().toString(), 'ToggleAll()'); }); }); }); diff --git a/bloc_library/test/blocs/todos_state_test.dart b/bloc_library/test/blocs/todos_state_test.dart index 878cfd3f..87ded732 100644 --- a/bloc_library/test/blocs/todos_state_test.dart +++ b/bloc_library/test/blocs/todos_state_test.dart @@ -1,19 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter_test/flutter_test.dart'; import 'package:bloc_library/blocs/blocs.dart'; import 'package:bloc_library/models/models.dart'; +import 'package:flutter_test/flutter_test.dart'; void main() { group('TodosState', () { group('TodosLoading', () { test('toString returns correct value', () { - expect( - TodosLoading().toString(), - 'TodosLoading', - ); + expect(TodosLoading().toString(), 'TodosLoading()'); }); }); @@ -28,10 +21,7 @@ void main() { group('TodosNotLoaded', () { test('toString returns correct value', () { - expect( - TodosNotLoaded().toString(), - 'TodosNotLoaded', - ); + expect(TodosNotLoaded().toString(), 'TodosNotLoaded()'); }); }); }); diff --git a/bloc_library/test/localization_test.dart b/bloc_library/test/localization_test.dart index 73c8e1ba..0cb1f2f5 100644 --- a/bloc_library/test/localization_test.dart +++ b/bloc_library/test/localization_test.dart @@ -1,15 +1,11 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter_test/flutter_test.dart'; import 'package:bloc_library/localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; void main() { group('FlutterBlocLocalizations', () { - FlutterBlocLocalizations localizations; - FlutterBlocLocalizationsDelegate delegate; + late FlutterBlocLocalizations localizations; + late FlutterBlocLocalizationsDelegate delegate; setUp(() { localizations = FlutterBlocLocalizations(); @@ -21,7 +17,7 @@ void main() { }); test('shouldReload returns false', () { - expect(delegate.shouldReload(null), false); + expect(delegate.shouldReload(FlutterBlocLocalizationsDelegate()), false); }); test('isSupported returns true for english', () { diff --git a/bloc_library/test/models/todo_test.dart b/bloc_library/test/models/todo_test.dart index 8e2eb5b0..85da9a2d 100644 --- a/bloc_library/test/models/todo_test.dart +++ b/bloc_library/test/models/todo_test.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter_test/flutter_test.dart'; import 'package:bloc_library/models/models.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; diff --git a/bloc_library/test/screens/add_edit_screen_test.dart b/bloc_library/test/screens/add_edit_screen_test.dart index 6a753343..233f39a3 100644 --- a/bloc_library/test/screens/add_edit_screen_test.dart +++ b/bloc_library/test/screens/add_edit_screen_test.dart @@ -1,24 +1,21 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:bloc_library/localization.dart'; +import 'package:bloc_library/models/models.dart'; +import 'package:bloc_library/screens/add_edit_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:bloc_library/screens/add_edit_screen.dart'; -import 'package:bloc_library/models/models.dart'; -import 'package:bloc_library/localization.dart'; import 'package:todos_app_core/todos_app_core.dart'; void main() { group('AddEditScreen', () { - testWidgets('should render properly when isEditing: true', - (WidgetTester tester) async { + testWidgets('should render properly when isEditing: true', ( + WidgetTester tester, + ) async { await tester.pumpWidget( MaterialApp( home: Scaffold( body: AddEditScreen( isEditing: true, - onSave: (_, __) {}, + onSave: (_, _) {}, todo: Todo('wash dishes', id: '0'), ), ), @@ -34,15 +31,13 @@ void main() { expect(find.byKey(ArchSampleKeys.saveTodoFab), findsOneWidget); }); - testWidgets('should render properly when isEditing: false', - (WidgetTester tester) async { + testWidgets('should render properly when isEditing: false', ( + WidgetTester tester, + ) async { await tester.pumpWidget( MaterialApp( home: Scaffold( - body: AddEditScreen( - isEditing: false, - onSave: (_, __) {}, - ), + body: AddEditScreen(isEditing: false, onSave: (_, _) {}), ), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), @@ -55,15 +50,16 @@ void main() { expect(find.byKey(ArchSampleKeys.saveNewTodo), findsOneWidget); }); - testWidgets('should call onSave when Floating Action Button is tapped', - (WidgetTester tester) async { + testWidgets('should call onSave when Floating Action Button is tapped', ( + WidgetTester tester, + ) async { var onSavePressed = false; await tester.pumpWidget( MaterialApp( home: Scaffold( body: AddEditScreen( isEditing: true, - onSave: (_, __) { + onSave: (_, _) { onSavePressed = true; }, todo: Todo('wash dishes'), @@ -80,14 +76,15 @@ void main() { expect(onSavePressed, true); }); - testWidgets('should call show error if task name is empty', - (WidgetTester tester) async { + testWidgets('should call show error if task name is empty', ( + WidgetTester tester, + ) async { await tester.pumpWidget( MaterialApp( home: Scaffold( body: AddEditScreen( isEditing: true, - onSave: (_, __) {}, + onSave: (_, _) {}, todo: Todo('wash dishes'), ), ), diff --git a/bloc_library/test/screens/details_screen_test.dart b/bloc_library/test/screens/details_screen_test.dart index a8c5a282..6fa1a3da 100644 --- a/bloc_library/test/screens/details_screen_test.dart +++ b/bloc_library/test/screens/details_screen_test.dart @@ -1,17 +1,13 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:bloc_library/bloc_library_keys.dart'; +import 'package:bloc_library/blocs/todos/todos.dart'; +import 'package:bloc_library/localization.dart'; +import 'package:bloc_library/models/models.dart'; +import 'package:bloc_library/screens/screens.dart'; import 'package:bloc_test/bloc_test.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:bloc_library/blocs/todos/todos.dart'; -import 'package:bloc_library/screens/screens.dart'; -import 'package:bloc_library/models/models.dart'; -import 'package:bloc_library/bloc_library_keys.dart'; -import 'package:bloc_library/localization.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:todos_app_core/todos_app_core.dart'; class MockTodosBloc extends MockBloc @@ -19,7 +15,7 @@ class MockTodosBloc extends MockBloc void main() { group('DetailsScreen', () { - TodosBloc todosBloc; + late TodosBloc todosBloc; setUp(() { todosBloc = MockTodosBloc(); @@ -30,14 +26,12 @@ void main() { }); testWidgets('renders properly with no todos', (WidgetTester tester) async { - when(todosBloc.state).thenReturn(TodosLoaded([])); + when(() => todosBloc.state).thenReturn(TodosLoaded([])); await tester.pumpWidget( BlocProvider.value( value: todosBloc, child: MaterialApp( - home: Scaffold( - body: DetailsScreen(id: '0'), - ), + home: Scaffold(body: DetailsScreen(id: '0')), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -50,16 +44,14 @@ void main() { }); testWidgets('renders properly with todos', (WidgetTester tester) async { - when(todosBloc.state).thenReturn( - TodosLoaded([Todo('wash car', id: '0')]), - ); + when( + () => todosBloc.state, + ).thenReturn(TodosLoaded([Todo('wash car', id: '0')])); await tester.pumpWidget( BlocProvider.value( value: todosBloc, child: MaterialApp( - home: Scaffold( - body: DetailsScreen(id: '0'), - ), + home: Scaffold(body: DetailsScreen(id: '0')), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -72,21 +64,22 @@ void main() { expect(find.text('wash car'), findsOneWidget); }); - testWidgets('adds UpdateTodo when checkbox tapped', - (WidgetTester tester) async { - when(todosBloc.state).thenReturn( - TodosLoaded([Todo('wash car', id: '0')]), - ); - when(todosBloc.add( - UpdateTodo(Todo('wash car', id: '0', complete: true)), - )).thenReturn(null); + testWidgets('adds UpdateTodo when checkbox tapped', ( + WidgetTester tester, + ) async { + when( + () => todosBloc.state, + ).thenReturn(TodosLoaded([Todo('wash car', id: '0')])); + when( + () => todosBloc.add( + UpdateTodo(Todo('wash car', id: '0', complete: true)), + ), + ).thenReturn(null); await tester.pumpWidget( BlocProvider.value( value: todosBloc, child: MaterialApp( - home: Scaffold( - body: DetailsScreen(id: '0'), - ), + home: Scaffold(body: DetailsScreen(id: '0')), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -96,23 +89,24 @@ void main() { ); await tester.pumpAndSettle(); await tester.tap(find.byKey(BlocLibraryKeys.detailsScreenCheckBox)); - verify(todosBloc.add( - UpdateTodo(Todo('wash car', id: '0', complete: true)), - )).called(1); + verify( + () => todosBloc.add( + UpdateTodo(Todo('wash car', id: '0', complete: true)), + ), + ).called(1); }); - testWidgets('Navigates to Edit Todo Screen when Edit Tapped', - (WidgetTester tester) async { - when(todosBloc.state).thenReturn( - TodosLoaded([Todo('wash car', id: '0')]), - ); + testWidgets('Navigates to Edit Todo Screen when Edit Tapped', ( + WidgetTester tester, + ) async { + when( + () => todosBloc.state, + ).thenReturn(TodosLoaded([Todo('wash car', id: '0')])); await tester.pumpWidget( BlocProvider.value( value: todosBloc, child: MaterialApp( - home: Scaffold( - body: DetailsScreen(id: '0'), - ), + home: Scaffold(body: DetailsScreen(id: '0')), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -126,21 +120,22 @@ void main() { expect(find.byKey(ArchSampleKeys.editTodoScreen), findsOneWidget); }); - testWidgets('adds UpdateTodo when onSave called', - (WidgetTester tester) async { - when(todosBloc.add( - UpdateTodo(Todo('new todo', id: '0', complete: true)), - )).thenReturn(null); - when(todosBloc.state).thenReturn( - TodosLoaded([Todo('wash car', id: '0')]), - ); + testWidgets('adds UpdateTodo when onSave called', ( + WidgetTester tester, + ) async { + when( + () => todosBloc.add( + UpdateTodo(Todo('new todo', id: '0', complete: true)), + ), + ).thenReturn(null); + when( + () => todosBloc.state, + ).thenReturn(TodosLoaded([Todo('wash car', id: '0')])); await tester.pumpWidget( BlocProvider.value( value: todosBloc, child: MaterialApp( - home: Scaffold( - body: DetailsScreen(id: '0'), - ), + home: Scaffold(body: DetailsScreen(id: '0')), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -156,9 +151,11 @@ void main() { await tester.enterText(find.byKey(ArchSampleKeys.taskField), 'new todo'); await tester.tap(find.byKey(ArchSampleKeys.saveTodoFab)); await tester.pumpAndSettle(); - verify(todosBloc.add( - UpdateTodo(Todo('new todo', id: '0', complete: false)), - )).called(1); + verify( + () => todosBloc.add( + UpdateTodo(Todo('new todo', id: '0', complete: false)), + ), + ).called(1); }); }); } diff --git a/bloc_library/test/screens/home_screen_test.dart b/bloc_library/test/screens/home_screen_test.dart index 7e1c0df1..a53f7684 100644 --- a/bloc_library/test/screens/home_screen_test.dart +++ b/bloc_library/test/screens/home_screen_test.dart @@ -1,26 +1,20 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:bloc_library/blocs/blocs.dart'; -import 'package:bloc_library/blocs/tab/tab_bloc.dart'; +import 'package:bloc_library/localization.dart'; import 'package:bloc_library/models/app_tab.dart'; +import 'package:bloc_library/models/visibility_filter.dart'; import 'package:bloc_library/screens/screens.dart'; import 'package:bloc_test/bloc_test.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:bloc_library/blocs/todos/todos.dart'; -import 'package:bloc_library/screens/home_screen.dart'; -import 'package:bloc_library/localization.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:todos_app_core/todos_app_core.dart'; class MockTodosBloc extends MockBloc implements TodosBloc {} class MockFilteredTodosBloc - extends MockBloc + extends MockBloc implements FilteredTodosBloc {} class MockTabBloc extends MockBloc implements TabBloc {} @@ -30,10 +24,10 @@ class MockStatsBloc extends MockBloc void main() { group('HomeScreen', () { - TodosBloc todosBloc; - FilteredTodosBloc filteredTodosBloc; - TabBloc tabBloc; - StatsBloc statsBloc; + late TodosBloc todosBloc; + late FilteredTodosBloc filteredTodosBloc; + late TabBloc tabBloc; + late StatsBloc statsBloc; setUp(() { todosBloc = MockTodosBloc(); @@ -43,28 +37,21 @@ void main() { }); testWidgets('renders correctly', (WidgetTester tester) async { - when(todosBloc.state).thenAnswer((_) => TodosLoaded([])); - when(tabBloc.state).thenAnswer((_) => AppTab.todos); + when(() => todosBloc.state).thenAnswer((_) => TodosLoaded([])); + when(() => tabBloc.state).thenAnswer((_) => AppTab.todos); + when( + () => filteredTodosBloc.state, + ).thenAnswer((_) => FilteredTodosLoaded([], VisibilityFilter.all)); await tester.pumpWidget( MultiBlocProvider( providers: [ - BlocProvider.value( - value: todosBloc, - ), - BlocProvider.value( - value: filteredTodosBloc, - ), - BlocProvider.value( - value: tabBloc, - ), - BlocProvider.value( - value: statsBloc, - ), + BlocProvider.value(value: todosBloc), + BlocProvider.value(value: filteredTodosBloc), + BlocProvider.value(value: tabBloc), + BlocProvider.value(value: statsBloc), ], child: MaterialApp( - home: Scaffold( - body: HomeScreen(), - ), + home: Scaffold(body: HomeScreen()), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -77,30 +64,24 @@ void main() { expect(find.text('Bloc Library Example'), findsOneWidget); }); - testWidgets('Navigates to /addTodo when Floating Action Button is tapped', - (WidgetTester tester) async { - when(todosBloc.state).thenAnswer((_) => TodosLoaded([])); - when(tabBloc.state).thenAnswer((_) => AppTab.todos); + testWidgets('Navigates to /addTodo when Floating Action Button is tapped', ( + WidgetTester tester, + ) async { + when(() => todosBloc.state).thenAnswer((_) => TodosLoaded([])); + when(() => tabBloc.state).thenAnswer((_) => AppTab.todos); + when( + () => filteredTodosBloc.state, + ).thenAnswer((_) => FilteredTodosLoaded([], VisibilityFilter.all)); await tester.pumpWidget( MultiBlocProvider( providers: [ - BlocProvider.value( - value: todosBloc, - ), - BlocProvider.value( - value: filteredTodosBloc, - ), - BlocProvider.value( - value: tabBloc, - ), - BlocProvider.value( - value: statsBloc, - ), + BlocProvider.value(value: todosBloc), + BlocProvider.value(value: filteredTodosBloc), + BlocProvider.value(value: tabBloc), + BlocProvider.value(value: statsBloc), ], child: MaterialApp( - home: Scaffold( - body: HomeScreen(), - ), + home: Scaffold(body: HomeScreen()), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), diff --git a/bloc_library/test/widgets/delete_todo_snack_bar_test.dart b/bloc_library/test/widgets/delete_todo_snack_bar_test.dart index ebfd057b..2655b0f5 100644 --- a/bloc_library/test/widgets/delete_todo_snack_bar_test.dart +++ b/bloc_library/test/widgets/delete_todo_snack_bar_test.dart @@ -1,40 +1,38 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:bloc_library/models/models.dart'; +import 'package:bloc_library/widgets/delete_todo_snack_bar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:bloc_library/widgets/delete_todo_snack_bar.dart'; -import 'package:bloc_library/models/models.dart'; void main() { group('DeleteTodoSnackBar', () { testWidgets('should render properly', (WidgetTester tester) async { var snackBarKey = Key('snack_bar_key'); var tapTarget = Key('tap_target_key'); - await tester.pumpWidget(MaterialApp( - home: Scaffold( - body: Builder(builder: (BuildContext context) { - return GestureDetector( - onTap: () { - Scaffold.of(context).showSnackBar(DeleteTodoSnackBar( - key: snackBarKey, - onUndo: () {}, - localizations: ArchSampleLocalizations(Locale('en')), - todo: Todo('take out trash'), - )); + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + DeleteTodoSnackBar( + key: snackBarKey, + onUndo: () {}, + localizations: ArchSampleLocalizations(Locale('en')), + todo: Todo('take out trash'), + ), + ); + }, + behavior: HitTestBehavior.opaque, + child: SizedBox(height: 500.0, width: 500.0, key: tapTarget), + ); }, - behavior: HitTestBehavior.opaque, - child: Container( - height: 100.0, - width: 100.0, - key: tapTarget, - ), - ); - }), + ), + ), ), - )); + ); await tester.tap(find.byKey(tapTarget)); await tester.pump(); @@ -49,27 +47,34 @@ void main() { expect(find.text('Undo'), findsOneWidget); }); - testWidgets('should call onUndo when undo tapped', - (WidgetTester tester) async { + testWidgets('should call onUndo when undo tapped', ( + WidgetTester tester, + ) async { var tapCount = 0; - await tester.pumpWidget(MaterialApp( - home: Scaffold( - body: Builder(builder: (BuildContext context) { - return GestureDetector( - onTap: () { - Scaffold.of(context).showSnackBar(DeleteTodoSnackBar( - onUndo: () { - ++tapCount; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + DeleteTodoSnackBar( + onUndo: () { + ++tapCount; + }, + localizations: ArchSampleLocalizations(Locale('en')), + todo: Todo('take out trash'), + ), + ); }, - localizations: ArchSampleLocalizations(Locale('en')), - todo: Todo('take out trash'), - )); + child: const Text('X'), + ); }, - child: const Text('X'), - ); - }), + ), + ), ), - )); + ); await tester.tap(find.text('X')); await tester.pump(); // start animation await tester.pump(const Duration(milliseconds: 750)); diff --git a/bloc_library/test/widgets/extra_actions_test.dart b/bloc_library/test/widgets/extra_actions_test.dart index 804d53e2..5a9aa696 100644 --- a/bloc_library/test/widgets/extra_actions_test.dart +++ b/bloc_library/test/widgets/extra_actions_test.dart @@ -1,17 +1,13 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:bloc_test/bloc_test.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:mockito/mockito.dart'; -import 'package:flutter/material.dart'; -import 'package:bloc_library/widgets/extra_actions.dart'; -import 'package:bloc_library/blocs/todos/todos.dart'; -import 'package:bloc_library/models/models.dart'; import 'package:bloc_library/bloc_library_keys.dart'; +import 'package:bloc_library/blocs/todos/todos.dart'; import 'package:bloc_library/localization.dart'; +import 'package:bloc_library/models/models.dart'; +import 'package:bloc_library/widgets/extra_actions.dart'; +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:todos_app_core/todos_app_core.dart'; class MockTodosBloc extends MockBloc @@ -19,106 +15,108 @@ class MockTodosBloc extends MockBloc void main() { group('ExtraActions', () { - TodosBloc todosBloc; + late TodosBloc todosBloc; setUp(() { todosBloc = MockTodosBloc(); }); - testWidgets('renders an empty Container if state is not TodosLoaded', - (WidgetTester tester) async { - when(todosBloc.state).thenReturn(TodosLoading()); + testWidgets('renders an empty Container if state is not TodosLoaded', ( + WidgetTester tester, + ) async { + when(() => todosBloc.state).thenReturn(TodosLoading()); await tester.pumpWidget( BlocProvider.value( value: todosBloc, child: MaterialApp( home: Scaffold( - appBar: AppBar( - actions: [ExtraActions()], - ), + appBar: AppBar(actions: [ExtraActions()]), body: Container(), ), ), ), ); - expect(find.byKey((BlocLibraryKeys.extraActionsEmptyContainer)), - findsOneWidget); + expect( + find.byKey((BlocLibraryKeys.extraActionsEmptyContainer)), + findsOneWidget, + ); }); testWidgets( - 'renders PopupMenuButton with mark all done if state is TodosLoaded with incomplete todos', - (WidgetTester tester) async { - when(todosBloc.state).thenReturn(TodosLoaded([Todo('walk dog')])); - await tester.pumpWidget( - BlocProvider.value( - value: todosBloc, - child: MaterialApp( - home: Scaffold( - appBar: AppBar( - actions: [ExtraActions()], + 'renders PopupMenuButton with mark all done if state is TodosLoaded with incomplete todos', + (WidgetTester tester) async { + when(() => todosBloc.state).thenReturn(TodosLoaded([Todo('walk dog')])); + await tester.pumpWidget( + BlocProvider.value( + value: todosBloc, + child: MaterialApp( + home: Scaffold( + appBar: AppBar(actions: [ExtraActions()]), + body: Container(), ), - body: Container(), + localizationsDelegates: [ + ArchSampleLocalizationsDelegate(), + FlutterBlocLocalizationsDelegate(), + ], ), - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - FlutterBlocLocalizationsDelegate(), - ], ), - ), - ); - await tester.pumpAndSettle(); - await tester.tap(find.byKey(BlocLibraryKeys.extraActionsPopupMenuButton)); - await tester.pump(); - expect(find.byKey(ArchSampleKeys.toggleAll), findsOneWidget); - expect(find.text('Clear completed'), findsOneWidget); - expect(find.text('Mark all complete'), findsOneWidget); - }); + ); + await tester.pumpAndSettle(); + await tester.tap( + find.byKey(BlocLibraryKeys.extraActionsPopupMenuButton), + ); + await tester.pump(); + expect(find.byKey(ArchSampleKeys.toggleAll), findsOneWidget); + expect(find.text('Clear completed'), findsOneWidget); + expect(find.text('Mark all complete'), findsOneWidget); + }, + ); testWidgets( - 'renders PopupMenuButton with mark all incomplete if state is TodosLoaded with complete todos', - (WidgetTester tester) async { - when(todosBloc.state) - .thenReturn(TodosLoaded([Todo('walk dog', complete: true)])); - await tester.pumpWidget( - BlocProvider.value( - value: todosBloc, - child: MaterialApp( - home: Scaffold( - appBar: AppBar( - actions: [ExtraActions()], + 'renders PopupMenuButton with mark all incomplete if state is TodosLoaded with complete todos', + (WidgetTester tester) async { + when( + () => todosBloc.state, + ).thenReturn(TodosLoaded([Todo('walk dog', complete: true)])); + await tester.pumpWidget( + BlocProvider.value( + value: todosBloc, + child: MaterialApp( + home: Scaffold( + appBar: AppBar(actions: [ExtraActions()]), + body: Container(), ), - body: Container(), + localizationsDelegates: [ + ArchSampleLocalizationsDelegate(), + FlutterBlocLocalizationsDelegate(), + ], ), - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - FlutterBlocLocalizationsDelegate(), - ], ), - ), - ); - await tester.pumpAndSettle(); - await tester.tap(find.byKey(BlocLibraryKeys.extraActionsPopupMenuButton)); - await tester.pump(); - expect(find.byKey(ArchSampleKeys.toggleAll), findsOneWidget); - expect(find.text('Clear completed'), findsOneWidget); - expect(find.text('Mark all incomplete'), findsOneWidget); - }); + ); + await tester.pumpAndSettle(); + await tester.tap( + find.byKey(BlocLibraryKeys.extraActionsPopupMenuButton), + ); + await tester.pump(); + expect(find.byKey(ArchSampleKeys.toggleAll), findsOneWidget); + expect(find.text('Clear completed'), findsOneWidget); + expect(find.text('Mark all incomplete'), findsOneWidget); + }, + ); - testWidgets('tapping clear completed adds ClearCompleted', - (WidgetTester tester) async { - when(todosBloc.state).thenReturn(TodosLoaded([ - Todo('walk dog'), - Todo('take out trash', complete: true), - ])); - when(todosBloc.add(ClearCompleted())).thenReturn(null); + testWidgets('tapping clear completed adds ClearCompleted', ( + WidgetTester tester, + ) async { + when(() => todosBloc.state).thenReturn( + TodosLoaded([Todo('walk dog'), Todo('take out trash', complete: true)]), + ); + when(() => todosBloc.add(ClearCompleted())).thenReturn(null); await tester.pumpWidget( BlocProvider.value( value: todosBloc, child: MaterialApp( home: Scaffold( - appBar: AppBar( - actions: [ExtraActions()], - ), + appBar: AppBar(actions: [ExtraActions()]), body: Container(), ), localizationsDelegates: [ @@ -134,24 +132,22 @@ void main() { expect(find.byKey(ArchSampleKeys.clearCompleted), findsOneWidget); await tester.pumpAndSettle(); await tester.tap(find.byKey(ArchSampleKeys.clearCompleted)); - verify(todosBloc.add(ClearCompleted())).called(1); + verify(() => todosBloc.add(ClearCompleted())).called(1); }); - testWidgets('tapping toggle all adds ToggleAll', - (WidgetTester tester) async { - when(todosBloc.state).thenReturn(TodosLoaded([ - Todo('walk dog'), - Todo('take out trash'), - ])); - when(todosBloc.add(ToggleAll())).thenReturn(null); + testWidgets('tapping toggle all adds ToggleAll', ( + WidgetTester tester, + ) async { + when( + () => todosBloc.state, + ).thenReturn(TodosLoaded([Todo('walk dog'), Todo('take out trash')])); + when(() => todosBloc.add(ToggleAll())).thenReturn(null); await tester.pumpWidget( BlocProvider.value( value: todosBloc, child: MaterialApp( home: Scaffold( - appBar: AppBar( - actions: [ExtraActions()], - ), + appBar: AppBar(actions: [ExtraActions()]), body: Container(), ), localizationsDelegates: [ @@ -167,7 +163,7 @@ void main() { expect(find.byKey(ArchSampleKeys.toggleAll), findsOneWidget); await tester.pumpAndSettle(); await tester.tap(find.byKey(ArchSampleKeys.toggleAll)); - verify(todosBloc.add(ToggleAll())).called(1); + verify(() => todosBloc.add(ToggleAll())).called(1); }); }); } diff --git a/bloc_library/test/widgets/filter_button_test.dart b/bloc_library/test/widgets/filter_button_test.dart index 46a85340..e53d6f0f 100644 --- a/bloc_library/test/widgets/filter_button_test.dart +++ b/bloc_library/test/widgets/filter_button_test.dart @@ -1,16 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:bloc_library/blocs/filtered_todos/filtered_todos.dart'; +import 'package:bloc_library/localization.dart'; +import 'package:bloc_library/models/models.dart'; +import 'package:bloc_library/widgets/filter_button.dart'; import 'package:bloc_test/bloc_test.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:bloc_library/blocs/filtered_todos/filtered_todos.dart'; -import 'package:bloc_library/widgets/filter_button.dart'; -import 'package:bloc_library/models/models.dart'; -import 'package:bloc_library/localization.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:todos_app_core/todos_app_core.dart'; class MockFilteredTodosBloc @@ -19,25 +15,24 @@ class MockFilteredTodosBloc void main() { group('FilterButton', () { - FilteredTodosBloc filteredTodosBloc; + late FilteredTodosBloc filteredTodosBloc; setUp(() { filteredTodosBloc = MockFilteredTodosBloc(); }); - testWidgets('should render properly with VisibilityFilter.all', - (WidgetTester tester) async { - when(filteredTodosBloc.state).thenAnswer( - (_) => FilteredTodosLoaded([], VisibilityFilter.all), - ); + testWidgets('should render properly with VisibilityFilter.all', ( + WidgetTester tester, + ) async { + when( + () => filteredTodosBloc.state, + ).thenAnswer((_) => FilteredTodosLoaded([], VisibilityFilter.all)); await tester.pumpWidget( BlocProvider.value( value: filteredTodosBloc, child: MaterialApp( home: Scaffold( - appBar: AppBar( - actions: [FilterButton(visible: true)], - ), + appBar: AppBar(actions: [FilterButton(visible: true)]), body: Container(), ), localizationsDelegates: [ @@ -56,19 +51,18 @@ void main() { expect(find.byKey(ArchSampleKeys.activeFilter), findsOneWidget); }); - testWidgets('should render properly VisibilityFilter.active', - (WidgetTester tester) async { - when(filteredTodosBloc.state).thenAnswer( - (_) => FilteredTodosLoaded([], VisibilityFilter.active), - ); + testWidgets('should render properly VisibilityFilter.active', ( + WidgetTester tester, + ) async { + when( + () => filteredTodosBloc.state, + ).thenAnswer((_) => FilteredTodosLoaded([], VisibilityFilter.active)); await tester.pumpWidget( BlocProvider.value( value: filteredTodosBloc, child: MaterialApp( home: Scaffold( - appBar: AppBar( - actions: [FilterButton(visible: true)], - ), + appBar: AppBar(actions: [FilterButton(visible: true)]), body: Container(), ), localizationsDelegates: [ @@ -87,19 +81,18 @@ void main() { expect(find.byKey(ArchSampleKeys.activeFilter), findsOneWidget); }); - testWidgets('should render properly VisibilityFilter.completed', - (WidgetTester tester) async { - when(filteredTodosBloc.state).thenAnswer( - (_) => FilteredTodosLoaded([], VisibilityFilter.completed), - ); + testWidgets('should render properly VisibilityFilter.completed', ( + WidgetTester tester, + ) async { + when( + () => filteredTodosBloc.state, + ).thenAnswer((_) => FilteredTodosLoaded([], VisibilityFilter.completed)); await tester.pumpWidget( BlocProvider.value( value: filteredTodosBloc, child: MaterialApp( home: Scaffold( - appBar: AppBar( - actions: [FilterButton(visible: true)], - ), + appBar: AppBar(actions: [FilterButton(visible: true)]), body: Container(), ), localizationsDelegates: [ @@ -118,21 +111,21 @@ void main() { expect(find.byKey(ArchSampleKeys.activeFilter), findsOneWidget); }); - testWidgets('should add UpdateFilter when filter selected', - (WidgetTester tester) async { - when(filteredTodosBloc.state).thenAnswer( - (_) => FilteredTodosLoaded([], VisibilityFilter.active), - ); - when(filteredTodosBloc.add(UpdateFilter(VisibilityFilter.all))) - .thenReturn(null); + testWidgets('should add UpdateFilter when filter selected', ( + WidgetTester tester, + ) async { + when( + () => filteredTodosBloc.state, + ).thenAnswer((_) => FilteredTodosLoaded([], VisibilityFilter.active)); + when( + () => filteredTodosBloc.add(UpdateFilter(VisibilityFilter.all)), + ).thenReturn(null); await tester.pumpWidget( BlocProvider.value( value: filteredTodosBloc, child: MaterialApp( home: Scaffold( - appBar: AppBar( - actions: [FilterButton(visible: true)], - ), + appBar: AppBar(actions: [FilterButton(visible: true)]), body: Container(), ), localizationsDelegates: [ @@ -152,8 +145,9 @@ void main() { expect(allFilterFinder, findsOneWidget); await tester.tap(allFilterFinder); - verify(filteredTodosBloc.add(UpdateFilter(VisibilityFilter.all))) - .called(1); + verify( + () => filteredTodosBloc.add(UpdateFilter(VisibilityFilter.all)), + ).called(1); }); }); } diff --git a/bloc_library/test/widgets/filtered_todos_test.dart b/bloc_library/test/widgets/filtered_todos_test.dart index 07be0cde..0b61dc29 100644 --- a/bloc_library/test/widgets/filtered_todos_test.dart +++ b/bloc_library/test/widgets/filtered_todos_test.dart @@ -1,17 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:bloc_library/blocs/blocs.dart'; +import 'package:bloc_library/localization.dart'; +import 'package:bloc_library/models/models.dart'; +import 'package:bloc_library/widgets/widgets.dart'; import 'package:bloc_test/bloc_test.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; -import 'package:bloc_library/blocs/blocs.dart'; -import 'package:bloc_library/widgets/widgets.dart'; -import 'package:bloc_library/models/models.dart'; -import 'package:bloc_library/bloc_library_keys.dart'; -import 'package:bloc_library/localization.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:todos_app_core/todos_app_core.dart'; class MockTodosBloc extends MockBloc @@ -23,19 +18,20 @@ class MockFilteredTodosBloc void main() { group('FilteredTodos', () { - TodosBloc todosBloc; - FilteredTodosBloc filteredTodosBloc; + late TodosBloc todosBloc; + late FilteredTodosBloc filteredTodosBloc; setUp(() { todosBloc = MockTodosBloc(); filteredTodosBloc = MockFilteredTodosBloc(); }); - testWidgets('should show loading indicator when state is TodosLoading', - (WidgetTester tester) async { - when(filteredTodosBloc.state).thenAnswer( - (_) => FilteredTodosLoading(), - ); + testWidgets('should show loading indicator when state is TodosLoading', ( + WidgetTester tester, + ) async { + when( + () => filteredTodosBloc.state, + ).thenAnswer((_) => FilteredTodosLoading()); await tester.pumpWidget( MultiBlocProvider( providers: [ @@ -43,9 +39,7 @@ void main() { BlocProvider.value(value: filteredTodosBloc), ], child: MaterialApp( - home: Scaffold( - body: FilteredTodos(), - ), + home: Scaffold(body: FilteredTodos()), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -57,70 +51,46 @@ void main() { expect(find.byKey(ArchSampleKeys.todosLoading), findsOneWidget); }); - testWidgets('should show empty container when state is null', - (WidgetTester tester) async { - when(filteredTodosBloc.state).thenAnswer( - (_) => null, - ); - await tester.pumpWidget( - MultiBlocProvider( - providers: [ - BlocProvider.value(value: todosBloc), - BlocProvider.value(value: filteredTodosBloc), - ], - child: MaterialApp( - home: Scaffold( - body: FilteredTodos(), - ), - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - FlutterBlocLocalizationsDelegate(), - ], - ), - ), - ); - await tester.pumpAndSettle(); - expect(find.byKey(BlocLibraryKeys.filteredTodosEmptyContainer), - findsOneWidget); - }); - testWidgets( - 'should show empty list when state is TodosLoaded with no todos', - (WidgetTester tester) async { - when(todosBloc.state).thenAnswer((_) => TodosLoaded([])); - when(filteredTodosBloc.state).thenAnswer( - (_) => FilteredTodosLoaded([], VisibilityFilter.all), - ); - await tester.pumpWidget( - MultiBlocProvider( - providers: [ - BlocProvider.value(value: todosBloc), - BlocProvider.value(value: filteredTodosBloc), - ], - child: MaterialApp( - home: Scaffold( - body: FilteredTodos(), - ), - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - FlutterBlocLocalizationsDelegate(), + 'should show empty list when state is TodosLoaded with no todos', + (WidgetTester tester) async { + when(() => todosBloc.state).thenAnswer((_) => TodosLoaded([])); + when( + () => filteredTodosBloc.state, + ).thenAnswer((_) => FilteredTodosLoaded([], VisibilityFilter.all)); + await tester.pumpWidget( + MultiBlocProvider( + providers: [ + BlocProvider.value(value: todosBloc), + BlocProvider.value(value: filteredTodosBloc), ], + child: MaterialApp( + home: Scaffold(body: FilteredTodos()), + localizationsDelegates: [ + ArchSampleLocalizationsDelegate(), + FlutterBlocLocalizationsDelegate(), + ], + ), ), - ), - ); - await tester.pumpAndSettle(); - final todoListFinder = find.byKey(ArchSampleKeys.todoList); - expect(todoListFinder, findsOneWidget); - expect( + ); + await tester.pumpAndSettle(); + final todoListFinder = find.byKey(ArchSampleKeys.todoList); + expect(todoListFinder, findsOneWidget); + expect( (todoListFinder.evaluate().first.widget as ListView) .semanticChildCount, - 0); - }); + 0, + ); + }, + ); - testWidgets('should show todos when state is TodosLoaded with todos', - (WidgetTester tester) async { - when(todosBloc.state).thenAnswer((_) => TodosLoaded([Todo('wash car')])); - when(filteredTodosBloc.state).thenAnswer( + testWidgets('should show todos when state is TodosLoaded with todos', ( + WidgetTester tester, + ) async { + when( + () => todosBloc.state, + ).thenAnswer((_) => TodosLoaded([Todo('wash car')])); + when(() => filteredTodosBloc.state).thenAnswer( (_) => FilteredTodosLoaded([Todo('wash car')], VisibilityFilter.all), ); await tester.pumpWidget( @@ -130,9 +100,7 @@ void main() { BlocProvider.value(value: filteredTodosBloc), ], child: MaterialApp( - home: Scaffold( - body: FilteredTodos(), - ), + home: Scaffold(body: FilteredTodos()), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -144,21 +112,27 @@ void main() { final todoListFinder = find.byKey(ArchSampleKeys.todoList); expect(todoListFinder, findsOneWidget); expect( - (todoListFinder.evaluate().first.widget as ListView) - .semanticChildCount, - 1); + (todoListFinder.evaluate().first.widget as ListView).semanticChildCount, + 1, + ); }); - testWidgets('should add OnCheckboxChanged when checkbox tapped', - (WidgetTester tester) async { - when(todosBloc.state) - .thenAnswer((_) => TodosLoaded([Todo('wash car', id: '0')])); - when(filteredTodosBloc.state).thenAnswer( - (_) => FilteredTodosLoaded( - [Todo('wash car', id: '0')], VisibilityFilter.all), + testWidgets('should add OnCheckboxChanged when checkbox tapped', ( + WidgetTester tester, + ) async { + when( + () => todosBloc.state, + ).thenAnswer((_) => TodosLoaded([Todo('wash car', id: '0')])); + when(() => filteredTodosBloc.state).thenAnswer( + (_) => FilteredTodosLoaded([ + Todo('wash car', id: '0'), + ], VisibilityFilter.all), ); - when(todosBloc.add(UpdateTodo(Todo('wash car', id: '0', complete: true)))) - .thenReturn(null); + when( + () => todosBloc.add( + UpdateTodo(Todo('wash car', id: '0', complete: true)), + ), + ).thenReturn(null); await tester.pumpWidget( MultiBlocProvider( providers: [ @@ -166,9 +140,7 @@ void main() { BlocProvider.value(value: filteredTodosBloc), ], child: MaterialApp( - home: Scaffold( - body: FilteredTodos(), - ), + home: Scaffold(body: FilteredTodos()), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -183,17 +155,16 @@ void main() { expect(checkboxFinder, findsOneWidget); await tester.tap(checkboxFinder); verify( - todosBloc.add( - UpdateTodo( - Todo('wash car', id: '0', complete: true), - ), + () => todosBloc.add( + UpdateTodo(Todo('wash car', id: '0', complete: true)), ), ).called(1); }); - testWidgets('should add DeleteTodo when dismissed', - (WidgetTester tester) async { - when(filteredTodosBloc.state).thenReturn( + testWidgets('should add DeleteTodo when dismissed', ( + WidgetTester tester, + ) async { + when(() => filteredTodosBloc.state).thenReturn( FilteredTodosLoaded([Todo('wash car', id: '0')], VisibilityFilter.all), ); await tester.pumpWidget( @@ -203,9 +174,7 @@ void main() { BlocProvider.value(value: filteredTodosBloc), ], child: MaterialApp( - home: Scaffold( - body: FilteredTodos(), - ), + home: Scaffold(body: FilteredTodos()), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -217,19 +186,16 @@ void main() { final todoFinder = find.byKey(ArchSampleKeys.todoItem('0')); expect(todoFinder, findsOneWidget); (tester.widget(find.byKey(ArchSampleKeys.todoItem('0'))) as Dismissible) - .onDismissed(null); + .onDismissed!(DismissDirection.horizontal); verify( - todosBloc.add( - DeleteTodo( - Todo('wash car', id: '0'), - ), - ), + () => todosBloc.add(DeleteTodo(Todo('wash car', id: '0'))), ).called(1); }); - testWidgets('should add AddTodo when dismissed and Undo Tapped', - (WidgetTester tester) async { - when(filteredTodosBloc.state).thenReturn( + testWidgets('should add AddTodo when dismissed and Undo Tapped', ( + WidgetTester tester, + ) async { + when(() => filteredTodosBloc.state).thenReturn( FilteredTodosLoaded([Todo('wash car', id: '0')], VisibilityFilter.all), ); await tester.pumpWidget( @@ -239,9 +205,7 @@ void main() { BlocProvider.value(value: filteredTodosBloc), ], child: MaterialApp( - home: Scaffold( - body: FilteredTodos(), - ), + home: Scaffold(body: FilteredTodos()), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -253,33 +217,26 @@ void main() { final todoFinder = find.byKey(ArchSampleKeys.todoItem('0')); expect(todoFinder, findsOneWidget); (tester.widget(find.byKey(ArchSampleKeys.todoItem('0'))) as Dismissible) - .onDismissed(null); + .onDismissed!(DismissDirection.horizontal); await tester.pumpAndSettle(); verify( - todosBloc.add( - DeleteTodo( - Todo('wash car', id: '0'), - ), - ), + () => todosBloc.add(DeleteTodo(Todo('wash car', id: '0'))), ).called(1); expect(find.text('Undo'), findsOneWidget); await tester.tap(find.text('Undo')); - verify( - todosBloc.add( - AddTodo( - Todo('wash car', id: '0'), - ), - ), - ).called(1); + verify(() => todosBloc.add(AddTodo(Todo('wash car', id: '0')))).called(1); }); - testWidgets('should Navigate to DetailsScreen when todo tapped', - (WidgetTester tester) async { - when(todosBloc.state) - .thenAnswer((_) => TodosLoaded([Todo('wash car', id: '0')])); - when(filteredTodosBloc.state).thenAnswer( - (_) => FilteredTodosLoaded( - [Todo('wash car', id: '0')], VisibilityFilter.all), + testWidgets('should Navigate to DetailsScreen when todo tapped', ( + WidgetTester tester, + ) async { + when( + () => todosBloc.state, + ).thenAnswer((_) => TodosLoaded([Todo('wash car', id: '0')])); + when(() => filteredTodosBloc.state).thenAnswer( + (_) => FilteredTodosLoaded([ + Todo('wash car', id: '0'), + ], VisibilityFilter.all), ); await tester.pumpWidget( MultiBlocProvider( @@ -288,9 +245,7 @@ void main() { BlocProvider.value(value: filteredTodosBloc), ], child: MaterialApp( - home: Scaffold( - body: FilteredTodos(), - ), + home: Scaffold(body: FilteredTodos()), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -306,16 +261,20 @@ void main() { expect(find.byKey(ArchSampleKeys.todoDetailsScreen), findsOneWidget); }); - testWidgets('should add DeleteTodo when todo deleted from DetailsScreen', - (WidgetTester tester) async { - when(todosBloc.state) - .thenAnswer((_) => TodosLoaded([Todo('wash car', id: '0')])); - when(filteredTodosBloc.state).thenAnswer( - (_) => FilteredTodosLoaded( - [Todo('wash car', id: '0')], VisibilityFilter.all), + testWidgets('should add DeleteTodo when todo deleted from DetailsScreen', ( + WidgetTester tester, + ) async { + when( + () => todosBloc.state, + ).thenAnswer((_) => TodosLoaded([Todo('wash car', id: '0')])); + when(() => filteredTodosBloc.state).thenAnswer( + (_) => FilteredTodosLoaded([ + Todo('wash car', id: '0'), + ], VisibilityFilter.all), ); - when(todosBloc.add(DeleteTodo(Todo('wash car', id: '0')))) - .thenReturn(null); + when( + () => todosBloc.add(DeleteTodo(Todo('wash car', id: '0'))), + ).thenReturn(null); await tester.pumpWidget( MultiBlocProvider( providers: [ @@ -323,9 +282,7 @@ void main() { BlocProvider.value(value: filteredTodosBloc), ], child: MaterialApp( - home: Scaffold( - body: FilteredTodos(), - ), + home: Scaffold(body: FilteredTodos()), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -342,66 +299,58 @@ void main() { await tester.tap(find.byKey(ArchSampleKeys.deleteTodoButton)); await tester.pumpAndSettle(); verify( - todosBloc.add( - DeleteTodo( - Todo('wash car', id: '0'), - ), - ), + () => todosBloc.add(DeleteTodo(Todo('wash car', id: '0'))), ).called(1); }); testWidgets( - 'should add AddTodo when todo deleted from DetailsScreen and Undo Tapped', - (WidgetTester tester) async { - when(todosBloc.state) - .thenAnswer((_) => TodosLoaded([Todo('wash car', id: '0')])); - when(filteredTodosBloc.state).thenAnswer( - (_) => FilteredTodosLoaded( - [Todo('wash car', id: '0')], VisibilityFilter.all), - ); - when(todosBloc.add(DeleteTodo(Todo('wash car', id: '0')))) - .thenReturn(null); - when(todosBloc.add(AddTodo(Todo('wash car', id: '0')))).thenReturn(null); - await tester.pumpWidget( - MultiBlocProvider( - providers: [ - BlocProvider.value(value: todosBloc), - BlocProvider.value(value: filteredTodosBloc), - ], - child: MaterialApp( - home: Scaffold( - body: FilteredTodos(), - ), - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - FlutterBlocLocalizationsDelegate(), - ], - ), - ), - ); - await tester.pumpAndSettle(); - final todoFinder = find.byKey(ArchSampleKeys.todoItem('0')); - expect(todoFinder, findsOneWidget); - await tester.tap(todoFinder); - await tester.pumpAndSettle(); - expect(find.byKey(ArchSampleKeys.todoDetailsScreen), findsOneWidget); - await tester.tap(find.byKey(ArchSampleKeys.deleteTodoButton)); - await tester.pumpAndSettle(); - verify( - todosBloc.add( - DeleteTodo( - Todo('wash car', id: '0'), - ), - ), - ).called(1); - await tester.tap(find.text('Undo')); - verify( - todosBloc.add( - AddTodo( + 'should add AddTodo when todo deleted from DetailsScreen and Undo Tapped', + (WidgetTester tester) async { + when( + () => todosBloc.state, + ).thenAnswer((_) => TodosLoaded([Todo('wash car', id: '0')])); + when(() => filteredTodosBloc.state).thenAnswer( + (_) => FilteredTodosLoaded([ Todo('wash car', id: '0'), + ], VisibilityFilter.all), + ); + when( + () => todosBloc.add(DeleteTodo(Todo('wash car', id: '0'))), + ).thenReturn(null); + when( + () => todosBloc.add(AddTodo(Todo('wash car', id: '0'))), + ).thenReturn(null); + await tester.pumpWidget( + MultiBlocProvider( + providers: [ + BlocProvider.value(value: todosBloc), + BlocProvider.value(value: filteredTodosBloc), + ], + child: MaterialApp( + home: Scaffold(body: FilteredTodos()), + localizationsDelegates: [ + ArchSampleLocalizationsDelegate(), + FlutterBlocLocalizationsDelegate(), + ], + ), ), - ), - ).called(1); - }); + ); + await tester.pumpAndSettle(); + final todoFinder = find.byKey(ArchSampleKeys.todoItem('0')); + expect(todoFinder, findsOneWidget); + await tester.tap(todoFinder); + await tester.pumpAndSettle(); + expect(find.byKey(ArchSampleKeys.todoDetailsScreen), findsOneWidget); + await tester.tap(find.byKey(ArchSampleKeys.deleteTodoButton)); + await tester.pumpAndSettle(); + verify( + () => todosBloc.add(DeleteTodo(Todo('wash car', id: '0'))), + ).called(1); + await tester.tap(find.text('Undo')); + verify( + () => todosBloc.add(AddTodo(Todo('wash car', id: '0'))), + ).called(1); + }, + ); }); } diff --git a/bloc_library/test/widgets/loading_indicator_test.dart b/bloc_library/test/widgets/loading_indicator_test.dart index 54c8713f..0bbfb755 100644 --- a/bloc_library/test/widgets/loading_indicator_test.dart +++ b/bloc_library/test/widgets/loading_indicator_test.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:bloc_library/widgets/loading_indicator.dart'; @@ -12,9 +8,7 @@ void main() { final loadingIndicatorKey = Key('loading_indicator_key'); await tester.pumpWidget( MaterialApp( - home: Scaffold( - body: LoadingIndicator(key: loadingIndicatorKey), - ), + home: Scaffold(body: LoadingIndicator(key: loadingIndicatorKey)), ), ); expect(find.byKey(loadingIndicatorKey), findsOneWidget); diff --git a/bloc_library/test/widgets/stats_tab_test.dart b/bloc_library/test/widgets/stats_tab_test.dart index 94182073..e48f9e4c 100644 --- a/bloc_library/test/widgets/stats_tab_test.dart +++ b/bloc_library/test/widgets/stats_tab_test.dart @@ -1,16 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:bloc_library/bloc_library_keys.dart'; +import 'package:bloc_library/blocs/stats/stats.dart'; +import 'package:bloc_library/localization.dart'; +import 'package:bloc_library/widgets/stats.dart'; import 'package:bloc_test/bloc_test.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:bloc_library/blocs/stats/stats.dart'; -import 'package:bloc_library/widgets/stats.dart'; -import 'package:bloc_library/bloc_library_keys.dart'; -import 'package:bloc_library/localization.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:todos_app_core/todos_app_core.dart'; class MockStatsBloc extends MockBloc @@ -18,22 +14,21 @@ class MockStatsBloc extends MockBloc void main() { group('Stats', () { - StatsBloc statsBloc; + late StatsBloc statsBloc; setUp(() { statsBloc = MockStatsBloc(); }); - testWidgets('should render LoadingIndicator when state is StatsLoading', - (WidgetTester tester) async { - when(statsBloc.state).thenAnswer((_) => StatsLoading()); + testWidgets('should render LoadingIndicator when state is StatsLoading', ( + WidgetTester tester, + ) async { + when(() => statsBloc.state).thenAnswer((_) => StatsLoading()); await tester.pumpWidget( BlocProvider.value( value: statsBloc, child: MaterialApp( - home: Scaffold( - body: Stats(), - ), + home: Scaffold(body: Stats()), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -45,37 +40,15 @@ void main() { expect(find.byKey(BlocLibraryKeys.statsLoadingIndicator), findsOneWidget); }); - testWidgets('should render empty stats container when state is null', - (WidgetTester tester) async { - when(statsBloc.state).thenAnswer((_) => null); - await tester.pumpWidget( - BlocProvider.value( - value: statsBloc, - child: MaterialApp( - home: Scaffold( - body: Stats(), - ), - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - FlutterBlocLocalizationsDelegate(), - ], - ), - ), - ); - await tester.pumpAndSettle(); - expect(find.byKey(BlocLibraryKeys.emptyStatsContainer), findsOneWidget); - }); - - testWidgets('should render correct stats when state is StatsLoaded(0, 0)', - (WidgetTester tester) async { - when(statsBloc.state).thenAnswer((_) => StatsLoaded(0, 0)); + testWidgets('should render correct stats when state is StatsLoaded(0, 0)', ( + WidgetTester tester, + ) async { + when(() => statsBloc.state).thenAnswer((_) => StatsLoaded(0, 0)); await tester.pumpWidget( BlocProvider.value( value: statsBloc, child: MaterialApp( - home: Scaffold( - body: Stats(), - ), + home: Scaffold(body: Stats()), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), @@ -93,16 +66,15 @@ void main() { expect((numCompletedFinder.evaluate().first.widget as Text).data, '0'); }); - testWidgets('should render correct stats when state is StatsLoaded(2, 1)', - (WidgetTester tester) async { - when(statsBloc.state).thenAnswer((_) => StatsLoaded(2, 1)); + testWidgets('should render correct stats when state is StatsLoaded(2, 1)', ( + WidgetTester tester, + ) async { + when(() => statsBloc.state).thenAnswer((_) => StatsLoaded(2, 1)); await tester.pumpWidget( BlocProvider.value( value: statsBloc, child: MaterialApp( - home: Scaffold( - body: Stats(), - ), + home: Scaffold(body: Stats()), localizationsDelegates: [ ArchSampleLocalizationsDelegate(), FlutterBlocLocalizationsDelegate(), diff --git a/bloc_library/test/widgets/tab_selector_test.dart b/bloc_library/test/widgets/tab_selector_test.dart index 98a3e7c3..66885ed0 100644 --- a/bloc_library/test/widgets/tab_selector_test.dart +++ b/bloc_library/test/widgets/tab_selector_test.dart @@ -1,13 +1,9 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:bloc_library/localization.dart'; +import 'package:bloc_library/models/models.dart'; +import 'package:bloc_library/widgets/tab_selector.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:bloc_library/localization.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:bloc_library/widgets/tab_selector.dart'; -import 'package:bloc_library/models/models.dart'; void main() { group('TabSelector', () { @@ -17,7 +13,7 @@ void main() { home: Scaffold( body: Container(), bottomNavigationBar: TabSelector( - onTabSelected: (_) => null, + onTabSelected: (_) {}, activeTab: AppTab.todos, ), ), @@ -32,36 +28,38 @@ void main() { expect(find.byKey(ArchSampleKeys.statsTab), findsOneWidget); }); - testWidgets('should call onTabSelected with correct index when tab tapped', - (WidgetTester tester) async { - AppTab selectedTab; + testWidgets( + 'should call onTabSelected with correct index when tab tapped', + (WidgetTester tester) async { + late AppTab selectedTab; - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Container(), - bottomNavigationBar: TabSelector( - onTabSelected: (appTab) { - selectedTab = appTab; - }, - activeTab: AppTab.todos, + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Container(), + bottomNavigationBar: TabSelector( + onTabSelected: (appTab) { + selectedTab = appTab; + }, + activeTab: AppTab.todos, + ), ), + localizationsDelegates: [ + ArchSampleLocalizationsDelegate(), + FlutterBlocLocalizationsDelegate(), + ], ), - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - FlutterBlocLocalizationsDelegate(), - ], - ), - ); - await tester.pumpAndSettle(); - final todoTabFinder = find.byKey(ArchSampleKeys.todoTab); - final statsTabFinder = find.byKey(ArchSampleKeys.statsTab); - expect(todoTabFinder, findsOneWidget); - expect(statsTabFinder, findsOneWidget); - await tester.tap(todoTabFinder); - expect(selectedTab, AppTab.todos); - await tester.tap(statsTabFinder); - expect(selectedTab, AppTab.stats); - }); + ); + await tester.pumpAndSettle(); + final todoTabFinder = find.byKey(ArchSampleKeys.todoTab); + final statsTabFinder = find.byKey(ArchSampleKeys.statsTab); + expect(todoTabFinder, findsOneWidget); + expect(statsTabFinder, findsOneWidget); + await tester.tap(todoTabFinder); + expect(selectedTab, AppTab.todos); + await tester.tap(statsTabFinder); + expect(selectedTab, AppTab.stats); + }, + ); }); } diff --git a/bloc_library/test/widgets/todo_item_test.dart b/bloc_library/test/widgets/todo_item_test.dart index 31089776..34b8c19f 100644 --- a/bloc_library/test/widgets/todo_item_test.dart +++ b/bloc_library/test/widgets/todo_item_test.dart @@ -1,25 +1,22 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:bloc_library/localization.dart'; +import 'package:bloc_library/models/models.dart'; +import 'package:bloc_library/widgets/todo_item.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:bloc_library/localization.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:bloc_library/widgets/todo_item.dart'; -import 'package:bloc_library/models/models.dart'; void main() { group('TodoItem', () { - testWidgets('should render properly with no note', - (WidgetTester tester) async { + testWidgets('should render properly with no note', ( + WidgetTester tester, + ) async { await tester.pumpWidget( MaterialApp( home: Scaffold( body: TodoItem( - onCheckboxChanged: (_) => null, - onDismissed: (_) => null, - onTap: () => null, + onCheckboxChanged: (_) {}, + onDismissed: (_) {}, + onTap: () {}, todo: Todo('wash car', id: '0'), ), ), @@ -35,15 +32,16 @@ void main() { expect(find.byKey(ArchSampleKeys.todoItemNote('0')), findsNothing); }); - testWidgets('should render properly with note', - (WidgetTester tester) async { + testWidgets('should render properly with note', ( + WidgetTester tester, + ) async { await tester.pumpWidget( MaterialApp( home: Scaffold( body: TodoItem( - onCheckboxChanged: (_) => null, - onDismissed: (_) => null, - onTap: () => null, + onCheckboxChanged: (_) {}, + onDismissed: (_) {}, + onTap: () {}, todo: Todo('wash car', note: 'some note', id: '0'), ), ), diff --git a/bloc_library/test_driver/integration_test.dart b/bloc_library/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/bloc_library/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/bloc_library/test_driver/todo_app.dart b/bloc_library/test_driver/todo_app.dart deleted file mode 100644 index 02d7642d..00000000 --- a/bloc_library/test_driver/todo_app.dart +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter_driver/driver_extension.dart'; -import 'package:bloc_library/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/bloc_library/test_driver/todo_app_test.dart b/bloc_library/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/bloc_library/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/bloc_library/web/favicon.png b/bloc_library/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/bloc_library/web/favicon.png differ diff --git a/bloc_library/web/icons/Icon-192.png b/bloc_library/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/bloc_library/web/icons/Icon-192.png differ diff --git a/bloc_library/web/icons/Icon-512.png b/bloc_library/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/bloc_library/web/icons/Icon-512.png differ diff --git a/bloc_library/web/icons/Icon-maskable-192.png b/bloc_library/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/bloc_library/web/icons/Icon-maskable-192.png differ diff --git a/bloc_library/web/icons/Icon-maskable-512.png b/bloc_library/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/bloc_library/web/icons/Icon-maskable-512.png differ diff --git a/bloc_library/web/manifest.json b/bloc_library/web/manifest.json new file mode 100644 index 00000000..a8a1f06f --- /dev/null +++ b/bloc_library/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "bloc_library", + "short_name": "bloc_library", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/bloc_library/windows/.gitignore b/bloc_library/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/bloc_library/windows/.gitignore @@ -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/ diff --git a/bloc_library/windows/CMakeLists.txt b/bloc_library/windows/CMakeLists.txt new file mode 100644 index 00000000..8419b22a --- /dev/null +++ b/bloc_library/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(bloc_library 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 "bloc_library") + +# 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) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_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 "$") +# 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) diff --git a/bloc_library/windows/flutter/CMakeLists.txt b/bloc_library/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/bloc_library/windows/flutter/CMakeLists.txt @@ -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} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/bloc_library/windows/flutter/generated_plugin_registrant.cc b/bloc_library/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/bloc_library/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/bloc_library/windows/flutter/generated_plugin_registrant.h b/bloc_library/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/bloc_library/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/bloc_library/windows/flutter/generated_plugins.cmake b/bloc_library/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/bloc_library/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +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 $) + 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) diff --git a/bloc_library/windows/runner/CMakeLists.txt b/bloc_library/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/bloc_library/windows/runner/CMakeLists.txt @@ -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) diff --git a/bloc_library/windows/runner/Runner.rc b/bloc_library/windows/runner/Runner.rc new file mode 100644 index 00000000..04376ab9 --- /dev/null +++ b/bloc_library/windows/runner/Runner.rc @@ -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", "com.example" "\0" + VALUE "FileDescription", "bloc_library" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "bloc_library" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "bloc_library.exe" "\0" + VALUE "ProductName", "bloc_library" "\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 diff --git a/bloc_library/windows/runner/flutter_window.cpp b/bloc_library/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/bloc_library/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#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( + 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 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); +} diff --git a/bloc_library/windows/runner/flutter_window.h b/bloc_library/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/bloc_library/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#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_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/bloc_library/windows/runner/main.cpp b/bloc_library/windows/runner/main.cpp new file mode 100644 index 00000000..fd60a2e1 --- /dev/null +++ b/bloc_library/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 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"bloc_library", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/bloc_library/windows/runner/resource.h b/bloc_library/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/bloc_library/windows/runner/resource.h @@ -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 diff --git a/bloc_library/windows/runner/resources/app_icon.ico b/bloc_library/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/bloc_library/windows/runner/resources/app_icon.ico differ diff --git a/bloc_library/windows/runner/runner.exe.manifest b/bloc_library/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/bloc_library/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/bloc_library/windows/runner/utils.cpp b/bloc_library/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/bloc_library/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +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 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::vector 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; +} diff --git a/bloc_library/windows/runner/utils.h b/bloc_library/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/bloc_library/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// 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, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/bloc_library/windows/runner/win32_window.cpp b/bloc_library/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/bloc_library/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#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(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( + 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(origin.x), + static_cast(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(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(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(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( + 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)); + } +} diff --git a/bloc_library/windows/runner/win32_window.h b/bloc_library/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/bloc_library/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// 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_ diff --git a/blocs/analysis_options.yaml b/blocs/analysis_options.yaml index 97d4b470..f798e77a 100644 --- a/blocs/analysis_options.yaml +++ b/blocs/analysis_options.yaml @@ -1,14 +1,32 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + analyzer: -# exclude: -# - path/to/excluded/files/** - -# Lint rules and documentation, see http://dart-lang.github.io/linter/lints -linter: - rules: - - cancel_subscriptions - - hash_and_equals - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - test_types_in_equals - - unrelated_type_equality_checks - - valid_regexps + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +# linter: +# rules: +# - camel_case_types + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/blocs/lib/blocs.dart b/blocs/lib/blocs.dart index eac5029b..4448606d 100644 --- a/blocs/lib/blocs.dart +++ b/blocs/lib/blocs.dart @@ -1,9 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library blocs; - export 'src/models/models.dart'; export 'src/stats_bloc.dart'; export 'src/todo_bloc.dart'; diff --git a/blocs/lib/src/models/models.dart b/blocs/lib/src/models/models.dart index 43a66686..19918b8b 100644 --- a/blocs/lib/src/models/models.dart +++ b/blocs/lib/src/models/models.dart @@ -1,6 +1,2 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - export 'package:blocs/src/models/todo.dart'; export 'package:blocs/src/models/visibility_filter.dart'; diff --git a/blocs/lib/src/models/todo.dart b/blocs/lib/src/models/todo.dart index 222d4111..42da5d40 100644 --- a/blocs/lib/src/models/todo.dart +++ b/blocs/lib/src/models/todo.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:blocs/src/uuid.dart'; import 'package:meta/meta.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -13,11 +9,10 @@ class Todo { final String note; final String task; - Todo(this.task, {this.complete = false, String note = '', String id}) - : this.note = note ?? '', - this.id = id ?? Uuid().generateV4(); + Todo(this.task, {this.complete = false, this.note = '', String? id}) + : id = id ?? Uuid().generateV4(); - Todo copyWith({bool complete, String id, String note, String task}) { + Todo copyWith({bool? complete, String? id, String? note, String? task}) { return Todo( task ?? this.task, complete: complete ?? this.complete, @@ -52,9 +47,9 @@ class Todo { static Todo fromEntity(TodoEntity entity) { return Todo( entity.task, - complete: entity.complete ?? false, + complete: entity.complete, note: entity.note, - id: entity.id ?? Uuid().generateV4(), + id: entity.id, ); } } diff --git a/blocs/lib/src/models/visibility_filter.dart b/blocs/lib/src/models/visibility_filter.dart index 11f11982..a47beca1 100644 --- a/blocs/lib/src/models/visibility_filter.dart +++ b/blocs/lib/src/models/visibility_filter.dart @@ -1,5 +1 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - enum VisibilityFilter { all, active, completed } diff --git a/blocs/lib/src/stats_bloc.dart b/blocs/lib/src/stats_bloc.dart index ed5e19bf..8cc2c975 100644 --- a/blocs/lib/src/stats_bloc.dart +++ b/blocs/lib/src/stats_bloc.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:blocs/src/models/models.dart'; @@ -11,10 +7,7 @@ class StatsBloc { final Stream numActive; final Stream numComplete; - StatsBloc._( - this.numActive, - this.numComplete, - ); + StatsBloc._(this.numActive, this.numComplete); factory StatsBloc(TodosInteractor interactor) { return StatsBloc._( diff --git a/blocs/lib/src/todo_bloc.dart b/blocs/lib/src/todo_bloc.dart index 0304ae3c..01c24a6a 100644 --- a/blocs/lib/src/todo_bloc.dart +++ b/blocs/lib/src/todo_bloc.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:blocs/src/models/models.dart'; @@ -48,6 +44,8 @@ class TodoBloc { void close() { deleteTodo.close(); updateTodo.close(); - _subscriptions.forEach((subscription) => subscription.cancel()); + for (var subscription in _subscriptions) { + subscription.cancel(); + } } } diff --git a/blocs/lib/src/todos_interactor.dart b/blocs/lib/src/todos_interactor.dart index 54526512..335c0bfc 100644 --- a/blocs/lib/src/todos_interactor.dart +++ b/blocs/lib/src/todos_interactor.dart @@ -1,10 +1,8 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:blocs/blocs.dart'; +import 'package:collection/collection.dart'; +import 'package:rxdart/rxdart.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; class TodosInteractor { @@ -19,12 +17,9 @@ class TodosInteractor { } Stream todo(String id) { - return todos.map((todos) { - return todos.firstWhere( - (todo) => todo.id == id, - orElse: () => null, - ); - }).where((todo) => todo != null); + return todos + .map((todos) => todos.firstWhereOrNull((todo) => todo.id == id)) + .whereNotNull(); } Stream get allComplete => todos.map(_allComplete); @@ -44,7 +39,8 @@ class TodosInteractor { final updates = await todos.map(_todosToUpdate).first; return Future.wait( - updates.map((update) => repository.updateTodo(update.toEntity()))); + updates.map((update) => repository.updateTodo(update.toEntity())), + ); } static bool _hasCompletedTodos(List todos) { diff --git a/blocs/lib/src/todos_list_bloc.dart b/blocs/lib/src/todos_list_bloc.dart index c9d27fd3..8de28133 100644 --- a/blocs/lib/src/todos_list_bloc.dart +++ b/blocs/lib/src/todos_list_bloc.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:blocs/src/models/models.dart'; @@ -113,7 +109,6 @@ class TodosListBloc { case VisibilityFilter.completed: return todo.complete; case VisibilityFilter.all: - default: return true; } }).toList(); @@ -129,6 +124,8 @@ class TodosListBloc { clearCompleted.close(); toggleAll.close(); updateTodo.close(); - _subscriptions.forEach((subscription) => subscription.cancel()); + for (var subscription in _subscriptions) { + subscription.cancel(); + } } } diff --git a/blocs/lib/src/user_bloc.dart b/blocs/lib/src/user_bloc.dart index c121d731..2dc34359 100644 --- a/blocs/lib/src/user_bloc.dart +++ b/blocs/lib/src/user_bloc.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -13,5 +9,5 @@ class UserBloc { Stream login() => _repository.login().asStream().asBroadcastStream(); - UserBloc(UserRepository repository) : this._repository = repository; + UserBloc(UserRepository repository) : _repository = repository; } diff --git a/blocs/lib/src/uuid.dart b/blocs/lib/src/uuid.dart index 1b6b26da..73d193cb 100644 --- a/blocs/lib/src/uuid.dart +++ b/blocs/lib/src/uuid.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:math'; /// A UUID generator, useful for generating unique IDs for your Todos. diff --git a/blocs/pubspec.yaml b/blocs/pubspec.yaml index c726bd9c..1d0529d4 100644 --- a/blocs/pubspec.yaml +++ b/blocs/pubspec.yaml @@ -1,14 +1,20 @@ name: blocs description: The Business Logic Components for a Todo App +version: 1.0.0 +publish_to: "none" environment: - sdk: '>=2.0.0-dev.28.0 <3.0.0' + sdk: ^3.9.0 dependencies: + collection: ^1.15.0 + meta: ^1.15.0 + rxdart: ^0.28.0 todos_repository_core: path: ../todos_repository_core - rxdart: ^0.23.1 dev_dependencies: - test: - mockito: + build_runner: ^2.4.13 + lints: ^6.0.0 + test: ^1.25.6 + mockito: ^5.5.0 diff --git a/blocs/test/all_tests.dart b/blocs/test/all_tests.dart deleted file mode 100644 index 416b9d98..00000000 --- a/blocs/test/all_tests.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'stats_bloc_test.dart' as statsBloc; -import 'todo_bloc_test.dart' as todoBloc; -import 'todos_bloc_test.dart' as todosBloc; -import 'todos_interactor_test.dart' as todosInteractor; - -void main() { - statsBloc.main(); - todoBloc.main(); - todosBloc.main(); - todosInteractor.main(); -} diff --git a/blocs/test/stats_bloc_test.dart b/blocs/test/stats_bloc_test.dart index d91973b1..0d00e2bc 100644 --- a/blocs/test/stats_bloc_test.dart +++ b/blocs/test/stats_bloc_test.dart @@ -1,22 +1,17 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:blocs/blocs.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:rxdart/rxdart.dart'; import 'package:test/test.dart'; -class MockTodosInteractor extends Mock implements TodosInteractor {} +import 'stats_bloc_test.mocks.dart'; +@GenerateNiceMocks([MockSpec()]) void main() { group('StatsBloc', () { test('should stream the number of active todos', () { final interactor = MockTodosInteractor(); - final todos = [ - Todo('Hallo', complete: true), - Todo('Friend'), - ]; + final todos = [Todo('Hallo', complete: true), Todo('Friend')]; final source = BehaviorSubject>.seeded(todos); when(interactor.todos).thenAnswer((_) => source.stream); diff --git a/blocs/test/stats_bloc_test.mocks.dart b/blocs/test/stats_bloc_test.mocks.dart new file mode 100644 index 00000000..85763905 --- /dev/null +++ b/blocs/test/stats_bloc_test.mocks.dart @@ -0,0 +1,134 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in blocs/test/stats_bloc_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; + +import 'package:blocs/blocs.dart' as _i3; +import 'package:mockito/mockito.dart' as _i1; +import 'package:todos_repository_core/todos_repository_core.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member + +class _FakeReactiveTodosRepository_0 extends _i1.SmartFake + implements _i2.ReactiveTodosRepository { + _FakeReactiveTodosRepository_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [TodosInteractor]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodosInteractor extends _i1.Mock implements _i3.TodosInteractor { + @override + _i2.ReactiveTodosRepository get repository => + (super.noSuchMethod( + Invocation.getter(#repository), + returnValue: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + returnValueForMissingStub: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + ) + as _i2.ReactiveTodosRepository); + + @override + _i4.Stream> get todos => + (super.noSuchMethod( + Invocation.getter(#todos), + returnValue: _i4.Stream>.empty(), + returnValueForMissingStub: _i4.Stream>.empty(), + ) + as _i4.Stream>); + + @override + _i4.Stream get allComplete => + (super.noSuchMethod( + Invocation.getter(#allComplete), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream get hasCompletedTodos => + (super.noSuchMethod( + Invocation.getter(#hasCompletedTodos), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream<_i3.Todo> todo(String? id) => + (super.noSuchMethod( + Invocation.method(#todo, [id]), + returnValue: _i4.Stream<_i3.Todo>.empty(), + returnValueForMissingStub: _i4.Stream<_i3.Todo>.empty(), + ) + as _i4.Stream<_i3.Todo>); + + @override + _i4.Future updateTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future addNewTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future deleteTodo(String? id) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [id]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future clearCompleted([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#clearCompleted, [_0]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future> toggleAll([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#toggleAll, [_0]), + returnValue: _i4.Future>.value([]), + returnValueForMissingStub: _i4.Future>.value( + [], + ), + ) + as _i4.Future>); +} diff --git a/blocs/test/todo_bloc_test.dart b/blocs/test/todo_bloc_test.dart index a545df1f..4afcacc0 100644 --- a/blocs/test/todo_bloc_test.dart +++ b/blocs/test/todo_bloc_test.dart @@ -1,12 +1,13 @@ import 'dart:async'; import 'package:blocs/blocs.dart'; -import 'package:blocs/src/models/models.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; -class MockTodosInteractor extends Mock implements TodosInteractor {} +import 'todo_bloc_test.mocks.dart'; +@GenerateNiceMocks([MockSpec()]) void main() { group('TodoBloc', () { test('should get the todo from the interactor', () { diff --git a/blocs/test/todo_bloc_test.mocks.dart b/blocs/test/todo_bloc_test.mocks.dart new file mode 100644 index 00000000..26f0615a --- /dev/null +++ b/blocs/test/todo_bloc_test.mocks.dart @@ -0,0 +1,134 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in blocs/test/todo_bloc_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; + +import 'package:blocs/blocs.dart' as _i3; +import 'package:mockito/mockito.dart' as _i1; +import 'package:todos_repository_core/todos_repository_core.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member + +class _FakeReactiveTodosRepository_0 extends _i1.SmartFake + implements _i2.ReactiveTodosRepository { + _FakeReactiveTodosRepository_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [TodosInteractor]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodosInteractor extends _i1.Mock implements _i3.TodosInteractor { + @override + _i2.ReactiveTodosRepository get repository => + (super.noSuchMethod( + Invocation.getter(#repository), + returnValue: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + returnValueForMissingStub: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + ) + as _i2.ReactiveTodosRepository); + + @override + _i4.Stream> get todos => + (super.noSuchMethod( + Invocation.getter(#todos), + returnValue: _i4.Stream>.empty(), + returnValueForMissingStub: _i4.Stream>.empty(), + ) + as _i4.Stream>); + + @override + _i4.Stream get allComplete => + (super.noSuchMethod( + Invocation.getter(#allComplete), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream get hasCompletedTodos => + (super.noSuchMethod( + Invocation.getter(#hasCompletedTodos), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream<_i3.Todo> todo(String? id) => + (super.noSuchMethod( + Invocation.method(#todo, [id]), + returnValue: _i4.Stream<_i3.Todo>.empty(), + returnValueForMissingStub: _i4.Stream<_i3.Todo>.empty(), + ) + as _i4.Stream<_i3.Todo>); + + @override + _i4.Future updateTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future addNewTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future deleteTodo(String? id) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [id]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future clearCompleted([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#clearCompleted, [_0]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future> toggleAll([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#toggleAll, [_0]), + returnValue: _i4.Future>.value([]), + returnValueForMissingStub: _i4.Future>.value( + [], + ), + ) + as _i4.Future>); +} diff --git a/blocs/test/todos_bloc_test.dart b/blocs/test/todos_bloc_test.dart index ec516124..24ef4fb7 100644 --- a/blocs/test/todos_bloc_test.dart +++ b/blocs/test/todos_bloc_test.dart @@ -1,20 +1,21 @@ import 'dart:async'; import 'package:blocs/blocs.dart'; -import 'package:blocs/src/models/models.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; -class MockReactiveTodosRepository extends Mock - implements ReactiveTodosRepository {} - -class MockTodosListInteractor extends Mock implements TodosInteractor {} +import 'todos_bloc_test.mocks.dart'; +@GenerateNiceMocks([ + MockSpec(), + MockSpec(), +]) void main() { group('TodosListBloc', () { test('should display all todos by default', () { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); final todos = [Todo('Hallo')]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); @@ -25,47 +26,32 @@ void main() { }); test('should display completed todos', () { - final interactor = MockTodosListInteractor(); - final todos = [ - Todo('Hallo'), - Todo('Friend', complete: true), - ]; + final interactor = MockTodosInteractor(); + final todos = [Todo('Hallo'), Todo('Friend', complete: true)]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); final bloc = TodosListBloc(interactor); bloc.updateFilter.add(VisibilityFilter.completed); - expect( - bloc.visibleTodos, - emitsThrough([todos.last]), - ); + expect(bloc.visibleTodos, emitsThrough([todos.last])); }); test('should display active todos', () { - final interactor = MockTodosListInteractor(); - final todos = [ - Todo('Hallo'), - Todo('Friend', complete: true), - ]; + final interactor = MockTodosInteractor(); + final todos = [Todo('Hallo'), Todo('Friend', complete: true)]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); final bloc = TodosListBloc(interactor); bloc.updateFilter.add(VisibilityFilter.active); - expect( - bloc.visibleTodos, - emitsThrough([todos.first]), - ); + expect(bloc.visibleTodos, emitsThrough([todos.first])); }); test('should stream the current visibility filter', () { - final interactor = MockTodosListInteractor(); - final todos = [ - Todo('Hallo'), - Todo('Friend', complete: true), - ]; + final interactor = MockTodosInteractor(); + final todos = [Todo('Hallo'), Todo('Friend', complete: true)]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); @@ -73,19 +59,18 @@ void main() { bloc.updateFilter.add(VisibilityFilter.completed); - expect( - bloc.activeFilter, - emits(VisibilityFilter.completed), - ); + expect(bloc.activeFilter, emits(VisibilityFilter.completed)); }); test('allComplete should stream from the interactor', () { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); - when(interactor.todos) - .thenAnswer((_) => Stream>.fromIterable([[]])); - when(interactor.allComplete) - .thenAnswer((_) => Stream.fromIterable([false])); + when( + interactor.todos, + ).thenAnswer((_) => Stream>.fromIterable([[]])); + when( + interactor.allComplete, + ).thenAnswer((_) => Stream.fromIterable([false])); final bloc = TodosListBloc(interactor); @@ -93,12 +78,14 @@ void main() { }); test('hasCompletedTodos should stream from the interactor', () { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); - when(interactor.todos) - .thenAnswer((_) => Stream>.fromIterable([[]])); - when(interactor.hasCompletedTodos) - .thenAnswer((_) => Stream.fromIterable([true])); + when( + interactor.todos, + ).thenAnswer((_) => Stream>.fromIterable([[]])); + when( + interactor.hasCompletedTodos, + ).thenAnswer((_) => Stream.fromIterable([true])); final bloc = TodosListBloc(interactor); @@ -106,12 +93,14 @@ void main() { }); test('should add todos to the interactor', () async { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); final todo = Todo('AddMe'); - when(interactor.todos).thenAnswer((_) => Stream.fromIterable([ - [todo] - ])); + when(interactor.todos).thenAnswer( + (_) => Stream.fromIterable([ + [todo], + ]), + ); when(interactor.addNewTodo(todo)).thenAnswer((_) => Future.value()); final bloc = TodosListBloc(interactor); @@ -121,10 +110,11 @@ void main() { }); test('should send deletions to the interactor', () async { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); - when(interactor.todos) - .thenAnswer((_) => Stream>.fromIterable([[]])); + when( + interactor.todos, + ).thenAnswer((_) => Stream>.fromIterable([[]])); when(interactor.deleteTodo('1')).thenAnswer((_) => Future.value()); final bloc = TodosListBloc(interactor); @@ -134,10 +124,11 @@ void main() { }); test('should remove completed todos from the interactor', () async { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); - when(interactor.todos) - .thenAnswer((_) => Stream>.fromIterable([[]])); + when( + interactor.todos, + ).thenAnswer((_) => Stream>.fromIterable([[]])); when(interactor.clearCompleted(null)).thenAnswer((_) => Future.value()); final bloc = TodosListBloc(interactor); @@ -147,12 +138,12 @@ void main() { }); test('should toggle all with the interactor', () async { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); - when(interactor.todos) - .thenAnswer((_) => Stream>.fromIterable([[]])); - when(interactor.toggleAll(null)) - .thenAnswer((_) => Future>.value()); + when( + interactor.todos, + ).thenAnswer((_) => Stream>.fromIterable([[]])); + when(interactor.toggleAll(null)).thenAnswer((_) async => []); final bloc = TodosListBloc(interactor); bloc.toggleAll.add(null); diff --git a/blocs/test/todos_bloc_test.mocks.dart b/blocs/test/todos_bloc_test.mocks.dart new file mode 100644 index 00000000..be89dd87 --- /dev/null +++ b/blocs/test/todos_bloc_test.mocks.dart @@ -0,0 +1,177 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in blocs/test/todos_bloc_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:blocs/blocs.dart' as _i5; +import 'package:mockito/mockito.dart' as _i1; +import 'package:todos_repository_core/src/todo_entity.dart' as _i4; +import 'package:todos_repository_core/todos_repository_core.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member + +class _FakeReactiveTodosRepository_0 extends _i1.SmartFake + implements _i2.ReactiveTodosRepository { + _FakeReactiveTodosRepository_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [ReactiveTodosRepository]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockReactiveTodosRepository extends _i1.Mock + implements _i2.ReactiveTodosRepository { + @override + _i3.Future addNewTodo(_i4.TodoEntity? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future deleteTodo(List? idList) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [idList]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Stream> todos() => + (super.noSuchMethod( + Invocation.method(#todos, []), + returnValue: _i3.Stream>.empty(), + returnValueForMissingStub: _i3.Stream>.empty(), + ) + as _i3.Stream>); + + @override + _i3.Future updateTodo(_i4.TodoEntity? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); +} + +/// A class which mocks [TodosInteractor]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodosInteractor extends _i1.Mock implements _i5.TodosInteractor { + @override + _i2.ReactiveTodosRepository get repository => + (super.noSuchMethod( + Invocation.getter(#repository), + returnValue: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + returnValueForMissingStub: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + ) + as _i2.ReactiveTodosRepository); + + @override + _i3.Stream> get todos => + (super.noSuchMethod( + Invocation.getter(#todos), + returnValue: _i3.Stream>.empty(), + returnValueForMissingStub: _i3.Stream>.empty(), + ) + as _i3.Stream>); + + @override + _i3.Stream get allComplete => + (super.noSuchMethod( + Invocation.getter(#allComplete), + returnValue: _i3.Stream.empty(), + returnValueForMissingStub: _i3.Stream.empty(), + ) + as _i3.Stream); + + @override + _i3.Stream get hasCompletedTodos => + (super.noSuchMethod( + Invocation.getter(#hasCompletedTodos), + returnValue: _i3.Stream.empty(), + returnValueForMissingStub: _i3.Stream.empty(), + ) + as _i3.Stream); + + @override + _i3.Stream<_i5.Todo> todo(String? id) => + (super.noSuchMethod( + Invocation.method(#todo, [id]), + returnValue: _i3.Stream<_i5.Todo>.empty(), + returnValueForMissingStub: _i3.Stream<_i5.Todo>.empty(), + ) + as _i3.Stream<_i5.Todo>); + + @override + _i3.Future updateTodo(_i5.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future addNewTodo(_i5.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future deleteTodo(String? id) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [id]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future clearCompleted([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#clearCompleted, [_0]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future> toggleAll([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#toggleAll, [_0]), + returnValue: _i3.Future>.value([]), + returnValueForMissingStub: _i3.Future>.value( + [], + ), + ) + as _i3.Future>); +} diff --git a/blocs/test/todos_interactor_test.dart b/blocs/test/todos_interactor_test.dart index 66eef7c7..d4603b3b 100644 --- a/blocs/test/todos_interactor_test.dart +++ b/blocs/test/todos_interactor_test.dart @@ -1,18 +1,15 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:blocs/blocs.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:rxdart/rxdart.dart'; import 'package:test/test.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; -class MockReactiveTodosRepository extends Mock - implements ReactiveTodosRepository {} +import 'todos_interactor_test.mocks.dart'; +@GenerateNiceMocks([MockSpec()]) void main() { group('TodosListInteractor', () { test('should convert repo entities into Todos', () { @@ -95,8 +92,9 @@ void main() { final todo = Todo("AddMe"); when(repository.todos()).thenAnswer((_) => Stream.empty()); - when(repository.addNewTodo(todo.toEntity())) - .thenAnswer((_) => Future.value()); + when( + repository.addNewTodo(todo.toEntity()), + ).thenAnswer((_) => Future.value()); interactor.addNewTodo(todo); @@ -144,8 +142,9 @@ void main() { ); when(repository.todos()).thenAnswer((_) => source.stream); - when(repository.updateTodo(e1Update)) - .thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e1Update), + ).thenAnswer((_) => Future.sync(() {})); await interactor.toggleAll(null); @@ -166,10 +165,12 @@ void main() { ); when(repository.todos()).thenAnswer((_) => source.stream); - when(repository.updateTodo(e1Update)) - .thenAnswer((_) => Future.sync(() {})); - when(repository.updateTodo(e2Update)) - .thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e1Update), + ).thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e2Update), + ).thenAnswer((_) => Future.sync(() {})); await interactor.toggleAll(null); @@ -191,10 +192,12 @@ void main() { ); when(repository.todos()).thenAnswer((_) => source.stream); - when(repository.updateTodo(e1Update)) - .thenAnswer((_) => Future.sync(() {})); - when(repository.updateTodo(e2Update)) - .thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e1Update), + ).thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e2Update), + ).thenAnswer((_) => Future.sync(() {})); await interactor.toggleAll(null); diff --git a/blocs/test/todos_interactor_test.mocks.dart b/blocs/test/todos_interactor_test.mocks.dart new file mode 100644 index 00000000..28248e98 --- /dev/null +++ b/blocs/test/todos_interactor_test.mocks.dart @@ -0,0 +1,67 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in blocs/test/todos_interactor_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:todos_repository_core/src/reactive_repository.dart' as _i2; +import 'package:todos_repository_core/src/todo_entity.dart' as _i4; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member + +/// A class which mocks [ReactiveTodosRepository]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockReactiveTodosRepository extends _i1.Mock + implements _i2.ReactiveTodosRepository { + @override + _i3.Future addNewTodo(_i4.TodoEntity? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future deleteTodo(List? idList) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [idList]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Stream> todos() => + (super.noSuchMethod( + Invocation.method(#todos, []), + returnValue: _i3.Stream>.empty(), + returnValueForMissingStub: _i3.Stream>.empty(), + ) + as _i3.Stream>); + + @override + _i3.Future updateTodo(_i4.TodoEntity? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); +} diff --git a/built_redux/.flutter-plugins-dependencies b/built_redux/.flutter-plugins-dependencies deleted file mode 100644 index 51c6a6c7..00000000 --- a/built_redux/.flutter-plugins-dependencies +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"android":[{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":[]}],"date_created":"2020-02-10 11:23:40.410802","version":"1.14.7-pre.38"} \ No newline at end of file diff --git a/built_redux/.gitignore b/built_redux/.gitignore deleted file mode 100644 index 2ddde2a5..00000000 --- a/built_redux/.gitignore +++ /dev/null @@ -1,73 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# 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 -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.packages -.pub-cache/ -.pub/ -/build/ - -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/built_redux/.metadata b/built_redux/.metadata deleted file mode 100644 index 1b5cec02..00000000 --- a/built_redux/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 27321ebbad34b0a3fafe99fac037102196d655ff - channel: stable - -project_type: app diff --git a/built_redux/README.md b/built_redux/README.md deleted file mode 100644 index 2d0bb162..00000000 --- a/built_redux/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# built_redux - -An example Todo app created with [built_value](https://pub.dartlang.org/packages/built_value), [built_redux](https://pub.dartlang.org/packages/built_redux), and [flutter_built_redux](https://pub.dartlang.org/packages/flutter_built_redux). - -## Key Concepts - - * Most of the Key Concepts from the [Redux Example](../redux) apply to this example as well, but the implementations are slightly different. - * To enforce immutability, `built_redux` apps require you to use a `built_value` Value Object. - * To increase discoverability, all actions are created using `built_redux` and attached to the `Store`. - * To use `built_value` and `built_redux`, you must add a `build.yaml` file to your project. - * To help with Type Safety, Reducers and Middleware can be created with `ReducerBuilder` and `MiddlewareBuilder` classes. - -## Enforcing Immutability - -The `State` objects in your app need to be created with `built_value`. `built_value` is a library that generate "Value Classes" from a Class template that you write. - -The Value classes can not be directly modified, but instead must be updated by creating a new version of the object. - -## Actions Discoverability - -One benefit of `built_redux` is that it attaches all possible actions to your store. This makes it very easy to see which actions are available for dispatch within your IDE using autocompletion. - -## Build.yaml - -In order to use `built_redux` and `built_value`, you need to create a `build.yaml` file in your project. Whenever you update your Value Classes or Redux Actions you'll need to run the build command: `flutter pub pub run build_runner build`. Instead of running the `build` command, you can run the `watch` command: `flutter pub pub run build_runner watch`. This will watch for changes and trigger a rebuild every time you make updates. This tends to be much faster overall. - -## Type Safety in Reducers and Middleware - -As your app grows, you'll want to break reducers and middleware down into smaller functions. - -## Differences to Redux - -These two libraries are incredibly similar. These are the minor differences: - - * Actions - - `built_redux` - Actions are generated for you by `built_redux` based on a definition. They are then attached to the Store upon creation. Each action has a unique name and a generic payload type. Each action can have at most one reducer. - - `Redux`, Actions are plain ol' Dart values, Classes or Enums. - * Reducers - - `built_redux` - Reducers are void functions that mutate a `StateBuilder`. The `StateBuilder` is then built after all reducers have run. Enforces immutability. - - `redux` - Reducers are functions in app state and latest action and return a new app state. Since immutability is not enforced, a user could simply mutate the state object instead of returning an updated copy. - - Both - Testing is easy, and both libraries have utilities for binding Reducers to Actions of a specific type. - * Middleware - - Very little difference here. Both libraries have utilities for binding actions of a specific type to a given Middleware. - * Nesting Large State Trees - - `built_redux` - Provides helpers for composing large Action trees that you can attach to your Store upon creation. Reducers can be combined via functional composition and by using utilities from the library. - - `redux` - No need for nesting actions, nesting reducers can be done via functional composition and by using utilities from the library. - - Both - allow you to break down your app into smaller units. - * Flutter integration - - `built_redux` - Maps from a `State` to `Prop`, which is passed to your `build` method along with your `Actions`. You combine the `Prop` wih the actions in the `build` method. - - `redux` - Maps from a `Store` to a `ViewModel`. The `ViewModel` should include both "Props" and callback functions that dispatch actions. - - Both - Store a Widget at the top of your tree containing your State. diff --git a/built_redux/android/.gitignore b/built_redux/android/.gitignore deleted file mode 100644 index bc2100d8..00000000 --- a/built_redux/android/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java diff --git a/built_redux/android/app/build.gradle b/built_redux/android/app/build.gradle deleted file mode 100644 index 6f68c33d..00000000 --- a/built_redux/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.built_redux" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/built_redux/android/app/src/debug/AndroidManifest.xml b/built_redux/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 6ac55600..00000000 --- a/built_redux/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/built_redux/android/app/src/main/AndroidManifest.xml b/built_redux/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 1aeedeb3..00000000 --- a/built_redux/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - diff --git a/built_redux/android/app/src/main/kotlin/com/example/built_redux/MainActivity.kt b/built_redux/android/app/src/main/kotlin/com/example/built_redux/MainActivity.kt deleted file mode 100644 index bd1f037e..00000000 --- a/built_redux/android/app/src/main/kotlin/com/example/built_redux/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.built_redux - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/built_redux/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/built_redux/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index a3f285f9..00000000 Binary files a/built_redux/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/built_redux/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/built_redux/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 5e6f3ac6..00000000 Binary files a/built_redux/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/built_redux/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/built_redux/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 144d60be..00000000 Binary files a/built_redux/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/built_redux/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/built_redux/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index deafae2d..00000000 Binary files a/built_redux/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/built_redux/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/built_redux/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index d5614ac8..00000000 Binary files a/built_redux/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/built_redux/android/app/src/main/res/values/styles.xml b/built_redux/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 00fa4417..00000000 --- a/built_redux/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/built_redux/android/app/src/profile/AndroidManifest.xml b/built_redux/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 6ac55600..00000000 --- a/built_redux/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/built_redux/android/build.gradle b/built_redux/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/built_redux/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/built_redux/android/gradle.properties b/built_redux/android/gradle.properties deleted file mode 100644 index 38c8d454..00000000 --- a/built_redux/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true -android.useAndroidX=true -android.enableJetifier=true diff --git a/built_redux/android/gradle/wrapper/gradle-wrapper.properties b/built_redux/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 296b146b..00000000 --- a/built_redux/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/built_redux/android/settings.gradle b/built_redux/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/built_redux/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/built_redux/ios/.gitignore b/built_redux/ios/.gitignore deleted file mode 100644 index e96ef602..00000000 --- a/built_redux/ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/built_redux/ios/Flutter/AppFrameworkInfo.plist b/built_redux/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6b4c0f78..00000000 --- a/built_redux/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/built_redux/ios/Flutter/Debug.xcconfig b/built_redux/ios/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba11..00000000 --- a/built_redux/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/built_redux/ios/Flutter/Release.xcconfig b/built_redux/ios/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340..00000000 --- a/built_redux/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/built_redux/ios/Podfile b/built_redux/ios/Podfile deleted file mode 100644 index b30a428b..00000000 --- a/built_redux/ios/Podfile +++ /dev/null @@ -1,90 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '9.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; - end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end - end - generated_key_values -end - -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; - - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' - - # Plugin Pods - - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') - end -end - -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - -post_install do |installer| - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end - end -end diff --git a/built_redux/ios/Runner.xcodeproj/project.pbxproj b/built_redux/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index d02225dc..00000000 --- a/built_redux/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,518 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.builtRedux; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.builtRedux; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.builtRedux; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/built_redux/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/built_redux/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140cf..00000000 --- a/built_redux/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/built_redux/ios/Runner/AppDelegate.swift b/built_redux/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a..00000000 --- a/built_redux/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d22f10b2..00000000 --- a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 980e5ad6..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index fd870289..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 75e84cd1..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 03ab8a84..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index a03431cb..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index f47613ee..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 7f2230a9..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 42315c6d..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index f9882cc0..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 45537513..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 6360ea17..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 152d5e12..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 310b0b8f..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 092b7bfe..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/built_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/built_redux/ios/Runner/Info.plist b/built_redux/ios/Runner/Info.plist deleted file mode 100644 index fcf21c99..00000000 --- a/built_redux/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - built_redux - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/built_redux/ios/Runner/Runner-Bridging-Header.h b/built_redux/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 7335fdf9..00000000 --- a/built_redux/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file diff --git a/built_redux/lib/actions/actions.dart b/built_redux/lib/actions/actions.dart deleted file mode 100644 index c9592c98..00000000 --- a/built_redux/lib/actions/actions.dart +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library actions; - -import 'package:built_redux/built_redux.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_value/built_value.dart'; -import 'package:built_value/serializer.dart'; - -part 'actions.g.dart'; - -abstract class AppActions extends ReduxActions { - ActionDispatcher addTodoAction; - ActionDispatcher clearCompletedAction; - ActionDispatcher deleteTodoAction; - ActionDispatcher fetchTodosAction; - ActionDispatcher toggleAllAction; - ActionDispatcher> loadTodosSuccess; - ActionDispatcher loadTodosFailure; - ActionDispatcher updateFilterAction; - ActionDispatcher updateTabAction; - ActionDispatcher updateTodoAction; - - AppActions._(); - - factory AppActions() => _$AppActions(); -} - -abstract class UpdateTodoActionPayload - implements Built { - static Serializer get serializer => - _$updateTodoActionPayloadSerializer; - - String get id; - - Todo get updatedTodo; - - UpdateTodoActionPayload._(); - - factory UpdateTodoActionPayload(String id, Todo updatedTodo) => - _$UpdateTodoActionPayload._( - id: id, - updatedTodo: updatedTodo, - ); -} diff --git a/built_redux/lib/actions/actions.g.dart b/built_redux/lib/actions/actions.g.dart deleted file mode 100644 index 025f841c..00000000 --- a/built_redux/lib/actions/actions.g.dart +++ /dev/null @@ -1,245 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of actions; - -// ************************************************************************** -// BuiltReduxGenerator -// ************************************************************************** - -// ignore_for_file: avoid_classes_with_only_static_members -// ignore_for_file: annotate_overrides -// ignore_for_file: overridden_fields -// ignore_for_file: type_annotate_public_apis - -class _$AppActions extends AppActions { - factory _$AppActions() => new _$AppActions._(); - _$AppActions._() : super._(); - - final addTodoAction = new ActionDispatcher('AppActions-addTodoAction'); - final clearCompletedAction = - new ActionDispatcher('AppActions-clearCompletedAction'); - final deleteTodoAction = - new ActionDispatcher('AppActions-deleteTodoAction'); - final fetchTodosAction = - new ActionDispatcher('AppActions-fetchTodosAction'); - final toggleAllAction = - new ActionDispatcher('AppActions-toggleAllAction'); - final loadTodosSuccess = - new ActionDispatcher>('AppActions-loadTodosSuccess'); - final loadTodosFailure = - new ActionDispatcher('AppActions-loadTodosFailure'); - final updateFilterAction = - new ActionDispatcher('AppActions-updateFilterAction'); - final updateTabAction = - new ActionDispatcher('AppActions-updateTabAction'); - final updateTodoAction = new ActionDispatcher( - 'AppActions-updateTodoAction'); - - @override - void setDispatcher(Dispatcher dispatcher) { - addTodoAction.setDispatcher(dispatcher); - clearCompletedAction.setDispatcher(dispatcher); - deleteTodoAction.setDispatcher(dispatcher); - fetchTodosAction.setDispatcher(dispatcher); - toggleAllAction.setDispatcher(dispatcher); - loadTodosSuccess.setDispatcher(dispatcher); - loadTodosFailure.setDispatcher(dispatcher); - updateFilterAction.setDispatcher(dispatcher); - updateTabAction.setDispatcher(dispatcher); - updateTodoAction.setDispatcher(dispatcher); - } -} - -class AppActionsNames { - static final addTodoAction = new ActionName('AppActions-addTodoAction'); - static final clearCompletedAction = - new ActionName('AppActions-clearCompletedAction'); - static final deleteTodoAction = - new ActionName('AppActions-deleteTodoAction'); - static final fetchTodosAction = - new ActionName('AppActions-fetchTodosAction'); - static final toggleAllAction = - new ActionName('AppActions-toggleAllAction'); - static final loadTodosSuccess = - new ActionName>('AppActions-loadTodosSuccess'); - static final loadTodosFailure = - new ActionName('AppActions-loadTodosFailure'); - static final updateFilterAction = - new ActionName('AppActions-updateFilterAction'); - static final updateTabAction = - new ActionName('AppActions-updateTabAction'); - static final updateTodoAction = - new ActionName('AppActions-updateTodoAction'); -} - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -Serializer _$updateTodoActionPayloadSerializer = - new _$UpdateTodoActionPayloadSerializer(); - -class _$UpdateTodoActionPayloadSerializer - implements StructuredSerializer { - @override - final Iterable types = const [ - UpdateTodoActionPayload, - _$UpdateTodoActionPayload - ]; - @override - final String wireName = 'UpdateTodoActionPayload'; - - @override - Iterable serialize( - Serializers serializers, UpdateTodoActionPayload object, - {FullType specifiedType = FullType.unspecified}) { - final result = [ - 'id', - serializers.serialize(object.id, specifiedType: const FullType(String)), - 'updatedTodo', - serializers.serialize(object.updatedTodo, - specifiedType: const FullType(Todo)), - ]; - - return result; - } - - @override - UpdateTodoActionPayload deserialize( - Serializers serializers, Iterable serialized, - {FullType specifiedType = FullType.unspecified}) { - final result = new UpdateTodoActionPayloadBuilder(); - - final iterator = serialized.iterator; - while (iterator.moveNext()) { - final key = iterator.current as String; - iterator.moveNext(); - final dynamic value = iterator.current; - switch (key) { - case 'id': - result.id = serializers.deserialize(value, - specifiedType: const FullType(String)) as String; - break; - case 'updatedTodo': - result.updatedTodo.replace(serializers.deserialize(value, - specifiedType: const FullType(Todo)) as Todo); - break; - } - } - - return result.build(); - } -} - -class _$UpdateTodoActionPayload extends UpdateTodoActionPayload { - @override - final String id; - @override - final Todo updatedTodo; - - factory _$UpdateTodoActionPayload( - [void Function(UpdateTodoActionPayloadBuilder) updates]) => - (new UpdateTodoActionPayloadBuilder()..update(updates)).build(); - - _$UpdateTodoActionPayload._({this.id, this.updatedTodo}) : super._() { - if (id == null) { - throw new BuiltValueNullFieldError('UpdateTodoActionPayload', 'id'); - } - if (updatedTodo == null) { - throw new BuiltValueNullFieldError( - 'UpdateTodoActionPayload', 'updatedTodo'); - } - } - - @override - UpdateTodoActionPayload rebuild( - void Function(UpdateTodoActionPayloadBuilder) updates) => - (toBuilder()..update(updates)).build(); - - @override - UpdateTodoActionPayloadBuilder toBuilder() => - new UpdateTodoActionPayloadBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - return other is UpdateTodoActionPayload && - id == other.id && - updatedTodo == other.updatedTodo; - } - - @override - int get hashCode { - return $jf($jc($jc(0, id.hashCode), updatedTodo.hashCode)); - } - - @override - String toString() { - return (newBuiltValueToStringHelper('UpdateTodoActionPayload') - ..add('id', id) - ..add('updatedTodo', updatedTodo)) - .toString(); - } -} - -class UpdateTodoActionPayloadBuilder - implements - Builder { - _$UpdateTodoActionPayload _$v; - - String _id; - String get id => _$this._id; - set id(String id) => _$this._id = id; - - TodoBuilder _updatedTodo; - TodoBuilder get updatedTodo => _$this._updatedTodo ??= new TodoBuilder(); - set updatedTodo(TodoBuilder updatedTodo) => _$this._updatedTodo = updatedTodo; - - UpdateTodoActionPayloadBuilder(); - - UpdateTodoActionPayloadBuilder get _$this { - if (_$v != null) { - _id = _$v.id; - _updatedTodo = _$v.updatedTodo?.toBuilder(); - _$v = null; - } - return this; - } - - @override - void replace(UpdateTodoActionPayload other) { - if (other == null) { - throw new ArgumentError.notNull('other'); - } - _$v = other as _$UpdateTodoActionPayload; - } - - @override - void update(void Function(UpdateTodoActionPayloadBuilder) updates) { - if (updates != null) updates(this); - } - - @override - _$UpdateTodoActionPayload build() { - _$UpdateTodoActionPayload _$result; - try { - _$result = _$v ?? - new _$UpdateTodoActionPayload._( - id: id, updatedTodo: updatedTodo.build()); - } catch (_) { - String _$failedField; - try { - _$failedField = 'updatedTodo'; - updatedTodo.build(); - } catch (e) { - throw new BuiltValueNestedFieldError( - 'UpdateTodoActionPayload', _$failedField, e.toString()); - } - rethrow; - } - replace(_$result); - return _$result; - } -} - -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new diff --git a/built_redux/lib/containers/action_selector.dart b/built_redux/lib/containers/action_selector.dart deleted file mode 100644 index e0b50dc1..00000000 --- a/built_redux/lib/containers/action_selector.dart +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_redux_sample/presentation/extra_actions_button.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_built_redux/flutter_built_redux.dart'; - -class ExtraActionSelector extends StoreConnector { - ExtraActionSelector({Key key}) : super(key: key); - - @override - bool connect(AppState state) => state.allCompleteSelector; - - @override - Widget build(BuildContext context, bool allComplete, AppActions actions) { - return ExtraActionsButton( - allComplete: allComplete, - onSelected: (action) { - if (action == ExtraAction.clearCompleted) { - actions.clearCompletedAction(); - } else if (action == ExtraAction.toggleAllComplete) { - actions.toggleAllAction(); - } - }, - ); - } -} diff --git a/built_redux/lib/containers/active_tab.dart b/built_redux/lib/containers/active_tab.dart deleted file mode 100644 index 94d3fd00..00000000 --- a/built_redux/lib/containers/active_tab.dart +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/containers/typedefs.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_built_redux/flutter_built_redux.dart'; - -class ActiveTab extends StoreConnector { - final ViewModelBuilder builder; - - ActiveTab({Key key, @required this.builder}) : super(key: key); - - @override - AppTab connect(AppState state) => state.activeTab; - - @override - Widget build(BuildContext context, AppTab activeTab, AppActions actions) { - return builder(context, activeTab); - } -} diff --git a/built_redux/lib/containers/add_todo.dart b/built_redux/lib/containers/add_todo.dart deleted file mode 100644 index 4433de41..00000000 --- a/built_redux/lib/containers/add_todo.dart +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_redux_sample/presentation/add_edit_screen.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_built_redux/flutter_built_redux.dart'; - -class AddTodo extends StoreConnector { - AddTodo({Key key}) : super(key: key); - - @override - Widget build(BuildContext context, Null ignored, AppActions actions) { - return AddEditScreen( - isEditing: false, - onSave: (String task, String note) { - actions.addTodoAction(Todo.builder((b) { - return b - ..task = task - ..note = note; - })); - }); - } - - @override - Null connect(AppState state) {} -} diff --git a/built_redux/lib/containers/app_loading.dart b/built_redux/lib/containers/app_loading.dart deleted file mode 100644 index a9acd400..00000000 --- a/built_redux/lib/containers/app_loading.dart +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/containers/typedefs.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_built_redux/flutter_built_redux.dart'; - -class AppLoading extends StoreConnector { - final ViewModelBuilder builder; - - AppLoading({Key key, @required this.builder}) : super(key: key); - - @override - Widget build(BuildContext context, bool state, AppActions actions) { - return builder(context, state); - } - - @override - bool connect(AppState state) { - return state.isLoading; - } -} diff --git a/built_redux/lib/containers/edit_todo.dart b/built_redux/lib/containers/edit_todo.dart deleted file mode 100644 index 0e7db71b..00000000 --- a/built_redux/lib/containers/edit_todo.dart +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_redux_sample/presentation/add_edit_screen.dart'; -import 'package:flutter/widgets.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:flutter_built_redux/flutter_built_redux.dart'; - -class EditTodo extends StoreConnector { - final Todo todo; - - EditTodo({this.todo, Key key}) : super(key: key); - - @override - Widget build(BuildContext context, _, AppActions actions) { - return AddEditScreen( - key: ArchSampleKeys.editTodoScreen, - isEditing: true, - onSave: (task, note) { - actions.updateTodoAction(UpdateTodoActionPayload( - todo.id, - todo.rebuild((b) => b - ..task = task - ..note = note))); - }, - todo: todo, - ); - } - - @override - Null connect(AppState state) {} -} diff --git a/built_redux/lib/containers/filter_selector.dart b/built_redux/lib/containers/filter_selector.dart deleted file mode 100644 index 20c3ddd4..00000000 --- a/built_redux/lib/containers/filter_selector.dart +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library filter_selector; - -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/containers/typedefs.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_value/built_value.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/src/widgets/framework.dart'; -import 'package:flutter_built_redux/flutter_built_redux.dart'; - -part 'filter_selector.g.dart'; - -typedef OnFilterSelected = void Function(VisibilityFilter filter); - -abstract class FilterSelectorViewModel - implements Built { - FilterSelectorViewModel._(); - - OnFilterSelected get onFilterSelected; - - VisibilityFilter get activeFilter; - - factory FilterSelectorViewModel( - [void Function(FilterSelectorViewModelBuilder b) updates]) = - _$FilterSelectorViewModel; - - factory FilterSelectorViewModel.from( - AppActions actions, - VisibilityFilter activeFilter, - ) { - return FilterSelectorViewModel((b) => b - ..onFilterSelected = (filter) { - actions.updateFilterAction(filter); - } - ..activeFilter = activeFilter); - } -} - -class FilterSelector - extends StoreConnector { - final ViewModelBuilder builder; - - @override - VisibilityFilter connect(AppState state) => state.activeFilter; - - FilterSelector({Key key, @required this.builder}) : super(key: key); - - @override - Widget build( - BuildContext context, - VisibilityFilter activeFilter, - AppActions actions, - ) { - return builder( - context, - FilterSelectorViewModel.from( - actions, - activeFilter, - ), - ); - } -} diff --git a/built_redux/lib/containers/filter_selector.g.dart b/built_redux/lib/containers/filter_selector.g.dart deleted file mode 100644 index 3001e3a9..00000000 --- a/built_redux/lib/containers/filter_selector.g.dart +++ /dev/null @@ -1,112 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of filter_selector; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -class _$FilterSelectorViewModel extends FilterSelectorViewModel { - @override - final OnFilterSelected onFilterSelected; - @override - final VisibilityFilter activeFilter; - - factory _$FilterSelectorViewModel( - [void Function(FilterSelectorViewModelBuilder) updates]) => - (new FilterSelectorViewModelBuilder()..update(updates)).build(); - - _$FilterSelectorViewModel._({this.onFilterSelected, this.activeFilter}) - : super._() { - if (onFilterSelected == null) { - throw new BuiltValueNullFieldError( - 'FilterSelectorViewModel', 'onFilterSelected'); - } - if (activeFilter == null) { - throw new BuiltValueNullFieldError( - 'FilterSelectorViewModel', 'activeFilter'); - } - } - - @override - FilterSelectorViewModel rebuild( - void Function(FilterSelectorViewModelBuilder) updates) => - (toBuilder()..update(updates)).build(); - - @override - FilterSelectorViewModelBuilder toBuilder() => - new FilterSelectorViewModelBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - final _$dynamicOther = other as dynamic; - return other is FilterSelectorViewModel && - onFilterSelected == _$dynamicOther.onFilterSelected && - activeFilter == other.activeFilter; - } - - @override - int get hashCode { - return $jf($jc($jc(0, onFilterSelected.hashCode), activeFilter.hashCode)); - } - - @override - String toString() { - return (newBuiltValueToStringHelper('FilterSelectorViewModel') - ..add('onFilterSelected', onFilterSelected) - ..add('activeFilter', activeFilter)) - .toString(); - } -} - -class FilterSelectorViewModelBuilder - implements - Builder { - _$FilterSelectorViewModel _$v; - - OnFilterSelected _onFilterSelected; - OnFilterSelected get onFilterSelected => _$this._onFilterSelected; - set onFilterSelected(OnFilterSelected onFilterSelected) => - _$this._onFilterSelected = onFilterSelected; - - VisibilityFilter _activeFilter; - VisibilityFilter get activeFilter => _$this._activeFilter; - set activeFilter(VisibilityFilter activeFilter) => - _$this._activeFilter = activeFilter; - - FilterSelectorViewModelBuilder(); - - FilterSelectorViewModelBuilder get _$this { - if (_$v != null) { - _onFilterSelected = _$v.onFilterSelected; - _activeFilter = _$v.activeFilter; - _$v = null; - } - return this; - } - - @override - void replace(FilterSelectorViewModel other) { - if (other == null) { - throw new ArgumentError.notNull('other'); - } - _$v = other as _$FilterSelectorViewModel; - } - - @override - void update(void Function(FilterSelectorViewModelBuilder) updates) { - if (updates != null) updates(this); - } - - @override - _$FilterSelectorViewModel build() { - final _$result = _$v ?? - new _$FilterSelectorViewModel._( - onFilterSelected: onFilterSelected, activeFilter: activeFilter); - replace(_$result); - return _$result; - } -} - -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new diff --git a/built_redux/lib/containers/filtered_todos.dart b/built_redux/lib/containers/filtered_todos.dart deleted file mode 100644 index 94806378..00000000 --- a/built_redux/lib/containers/filtered_todos.dart +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_redux_sample/presentation/todo_list.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_built_redux/flutter_built_redux.dart'; - -class FilteredTodos extends StoreConnector> { - FilteredTodos({Key key}) : super(key: key); - - @override - Widget build(BuildContext context, List state, AppActions actions) { - return TodoList( - todos: state, - onCheckboxChanged: (todo, complete) { - actions.updateTodoAction(UpdateTodoActionPayload( - todo.id, todo.rebuild((b) => b..complete = complete))); - }, - onRemove: (todo) { - actions.deleteTodoAction(todo.id); - }, - onUndoRemove: (todo) { - actions.addTodoAction(todo); - }, - ); - } - - @override - List connect(AppState state) => state.filteredTodosSelector; -} diff --git a/built_redux/lib/containers/stats.dart b/built_redux/lib/containers/stats.dart deleted file mode 100644 index 3f417a1e..00000000 --- a/built_redux/lib/containers/stats.dart +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library stats; - -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_redux_sample/presentation/stats_counter.dart'; -import 'package:built_value/built_value.dart'; -import 'package:flutter/src/widgets/framework.dart'; -import 'package:flutter_built_redux/flutter_built_redux.dart'; - -part 'stats.g.dart'; - -abstract class StatsProps implements Built { - int get numCompleted; - - int get numActive; - - StatsProps._(); - - factory StatsProps([Function(StatsPropsBuilder b) updates]) = _$StatsProps; -} - -class Stats extends StoreConnector { - Stats({Key key}) : super(key: key); - - @override - StatsProps connect(AppState state) { - return StatsProps((b) => b - ..numCompleted = state.numCompletedSelector - ..numActive = state.numActiveSelector); - } - - @override - Widget build(BuildContext context, StatsProps props, AppActions actions) { - return StatsCounter( - numActive: props.numActive, - numCompleted: props.numCompleted, - ); - } -} diff --git a/built_redux/lib/containers/stats.g.dart b/built_redux/lib/containers/stats.g.dart deleted file mode 100644 index b0e50bc9..00000000 --- a/built_redux/lib/containers/stats.g.dart +++ /dev/null @@ -1,100 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of stats; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -class _$StatsProps extends StatsProps { - @override - final int numCompleted; - @override - final int numActive; - - factory _$StatsProps([void Function(StatsPropsBuilder) updates]) => - (new StatsPropsBuilder()..update(updates)).build(); - - _$StatsProps._({this.numCompleted, this.numActive}) : super._() { - if (numCompleted == null) { - throw new BuiltValueNullFieldError('StatsProps', 'numCompleted'); - } - if (numActive == null) { - throw new BuiltValueNullFieldError('StatsProps', 'numActive'); - } - } - - @override - StatsProps rebuild(void Function(StatsPropsBuilder) updates) => - (toBuilder()..update(updates)).build(); - - @override - StatsPropsBuilder toBuilder() => new StatsPropsBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - return other is StatsProps && - numCompleted == other.numCompleted && - numActive == other.numActive; - } - - @override - int get hashCode { - return $jf($jc($jc(0, numCompleted.hashCode), numActive.hashCode)); - } - - @override - String toString() { - return (newBuiltValueToStringHelper('StatsProps') - ..add('numCompleted', numCompleted) - ..add('numActive', numActive)) - .toString(); - } -} - -class StatsPropsBuilder implements Builder { - _$StatsProps _$v; - - int _numCompleted; - int get numCompleted => _$this._numCompleted; - set numCompleted(int numCompleted) => _$this._numCompleted = numCompleted; - - int _numActive; - int get numActive => _$this._numActive; - set numActive(int numActive) => _$this._numActive = numActive; - - StatsPropsBuilder(); - - StatsPropsBuilder get _$this { - if (_$v != null) { - _numCompleted = _$v.numCompleted; - _numActive = _$v.numActive; - _$v = null; - } - return this; - } - - @override - void replace(StatsProps other) { - if (other == null) { - throw new ArgumentError.notNull('other'); - } - _$v = other as _$StatsProps; - } - - @override - void update(void Function(StatsPropsBuilder) updates) { - if (updates != null) updates(this); - } - - @override - _$StatsProps build() { - final _$result = _$v ?? - new _$StatsProps._(numCompleted: numCompleted, numActive: numActive); - replace(_$result); - return _$result; - } -} - -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new diff --git a/built_redux/lib/containers/tab_selector.dart b/built_redux/lib/containers/tab_selector.dart deleted file mode 100644 index 03bcb684..00000000 --- a/built_redux/lib/containers/tab_selector.dart +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/src/widgets/framework.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:flutter_built_redux/flutter_built_redux.dart'; - -typedef OnTabsSelected = void Function(int); - -class TabSelector extends StoreConnector { - TabSelector({Key key}) : super(key: key); - - @override - AppTab connect(AppState state) => state.activeTab; - - @override - Widget build(BuildContext context, AppTab activeTab, AppActions action) { - return BottomNavigationBar( - key: ArchSampleKeys.tabs, - currentIndex: AppTab.toIndex(activeTab), - onTap: (index) { - action.updateTabAction(AppTab.fromIndex(index)); - }, - items: AppTab.values.map((tab) { - return BottomNavigationBarItem( - icon: Icon( - tab == AppTab.todos ? Icons.list : Icons.show_chart, - key: tab == AppTab.stats - ? ArchSampleKeys.statsTab - : ArchSampleKeys.todoTab, - ), - title: Text(tab == AppTab.stats - ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos), - ); - }).toList(), - ); - } -} diff --git a/built_redux/lib/containers/todo_details.dart b/built_redux/lib/containers/todo_details.dart deleted file mode 100644 index 2b46373a..00000000 --- a/built_redux/lib/containers/todo_details.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_redux_sample/presentation/details_screen.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_built_redux/flutter_built_redux.dart'; - -class TodoDetails extends StoreConnector { - final String id; - - TodoDetails({Key key, @required this.id}) : super(key: key); - - @override - Widget build(BuildContext context, Todo todo, AppActions actions) { - return DetailsScreen( - todo: todo, - onDelete: () => actions.deleteTodoAction(todo.id), - toggleCompleted: (isComplete) { - actions.updateTodoAction(UpdateTodoActionPayload( - id, - todo.rebuild((b) => b..complete = isComplete), - )); - }, - ); - } - - @override - Todo connect(AppState state) { - return state.todos.firstWhere( - (todo) => todo.id == id, - orElse: () => Todo('Nothing Here'), - ); - } -} diff --git a/built_redux/lib/containers/typedefs.dart b/built_redux/lib/containers/typedefs.dart deleted file mode 100644 index 77ec69c8..00000000 --- a/built_redux/lib/containers/typedefs.dart +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/src/widgets/framework.dart'; - -typedef ViewModelBuilder = Widget Function( - BuildContext context, ViewModel vm); diff --git a/built_redux/lib/data/file_storage.dart b/built_redux/lib/data/file_storage.dart deleted file mode 100644 index cfe8f0aa..00000000 --- a/built_redux/lib/data/file_storage.dart +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_redux_sample/models/serializers.dart'; - -/// Loads and saves a List of Todos using a text file stored on the device. -class FileStorage { - final String tag; - final Future Function() getDirectory; - - const FileStorage( - this.tag, - this.getDirectory, - ); - - /// LoadTodos - Future> loadTodos() async { - final file = await _getLocalFile(); - final contents = await file.readAsString(); - - return serializers - .deserializeWith(AppState.serializer, json.decode(contents)) - .todos - .toList(); - } - - Future saveTodos(List todos) async { - final file = await _getLocalFile(); - - return file.writeAsString( - json.encode( - serializers.serializeWith( - AppState.serializer, - AppState.fromTodos(todos), - ), - ), - ); - } - - Future _getLocalFile() async { - final dir = await getDirectory(); - - return File('${dir.path}/FlutterMvcFileStorage__$tag.json'); - } - - Future clean() async { - final file = await _getLocalFile(); - - return file.delete(); - } -} diff --git a/built_redux/lib/data/todos_repository.dart b/built_redux/lib/data/todos_repository.dart deleted file mode 100644 index a40c2877..00000000 --- a/built_redux/lib/data/todos_repository.dart +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; -import 'dart:core'; - -import 'package:built_redux_sample/data/file_storage.dart'; -import 'package:built_redux_sample/data/web_client.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:path_provider/path_provider.dart'; - -/// A class that glues together our local file storage and web client. It has a -/// clear responsibility: Load Todos and Persist todos. -/// -/// In most apps, we use the provided repository. In this case, it makes sense -/// to demonstrate the built_value serializers, which are used in the -/// FileStorage part of this app. -/// -/// Please see the `todos_repository` library for more information about the -/// Repository pattern. -class TodosRepository { - final FileStorage fileStorage; - final WebClient webClient; - - const TodosRepository({ - this.fileStorage = const FileStorage( - '__built_redux_sample_app__', - getApplicationDocumentsDirectory, - ), - this.webClient = const WebClient(), - }); - - /// Loads todos first from File storage. If they don't exist or encounter an - /// error, it attempts to load the Todos from a Web Service. - Future> loadTodos() async { - try { - return await fileStorage.loadTodos(); - } catch (e) { - return webClient.fetchTodos(); - } - } - - // Persists todos to local disk and the web - Future saveTodos(List todos) { - return Future.wait([ - fileStorage.saveTodos(todos), - webClient.postTodos(todos), - ]); - } -} diff --git a/built_redux/lib/data/web_client.dart b/built_redux/lib/data/web_client.dart deleted file mode 100644 index 85eab7d0..00000000 --- a/built_redux/lib/data/web_client.dart +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:built_redux_sample/models/models.dart'; - -/// A class that is meant to represent a Web Service you would call to fetch -/// and persist Todos to and from the cloud. -/// -/// Since we're trying to keep this example simple, it doesn't communicate with -/// a real server but simply emulates the functionality. -class WebClient { - final Duration delay; - - const WebClient([this.delay = const Duration(milliseconds: 1200)]); - - /// Mock that "fetches" some Todos from a "web service" after a short delay - Future> fetchTodos() async { - return Future.delayed( - delay, - () => [ - Todo.builder( - (b) => b - ..task = 'Buy food for da kitty' - ..note = 'With the chickeny bits!' - ..id = '1', - ), - Todo.builder( - (b) => b - ..task = 'Find a Red Sea dive trip' - ..note = 'Echo vs MY Dream' - ..id = '2', - ), - Todo.builder( - (b) => b - ..task = 'Book flights to Egypt' - ..complete = true - ..id = '3', - ), - Todo.builder( - (b) => b - ..task = 'Decide on accommodation' - ..id = '4', - ), - Todo.builder( - (b) => b - ..task = 'Sip Margaritas' - ..note = 'on the beach' - ..complete = true - ..id = '5', - ), - ]); - } - - /// Mock that returns true or false for success or failure. In this case, - /// it will "Always Succeed" - Future postTodos(List todos) async { - return Future.value(true); - } -} diff --git a/built_redux/lib/localization.dart b/built_redux/lib/localization.dart deleted file mode 100644 index eb48df86..00000000 --- a/built_redux/lib/localization.dart +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter/material.dart'; - -class BuiltReduxLocalizations { - static BuiltReduxLocalizations of(BuildContext context) { - return Localizations.of( - context, - BuiltReduxLocalizations, - ); - } - - String get appTitle => 'Built Redux Example'; -} - -class BuiltReduxLocalizationsDelegate - extends LocalizationsDelegate { - @override - Future load(Locale locale) => - Future(() => BuiltReduxLocalizations()); - - @override - bool shouldReload(BuiltReduxLocalizationsDelegate old) => false; - - @override - bool isSupported(Locale locale) => - locale.languageCode.toLowerCase().contains('en'); -} diff --git a/built_redux/lib/main.dart b/built_redux/lib/main.dart deleted file mode 100644 index bbf0e2b0..00000000 --- a/built_redux/lib/main.dart +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library built_redux_sample; - -import 'package:built_redux/built_redux.dart'; -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/containers/add_todo.dart'; -import 'package:built_redux_sample/localization.dart'; -import 'package:built_redux_sample/middleware/store_todos_middleware.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_redux_sample/presentation/home_screen.dart'; -import 'package:built_redux_sample/reducers/reducers.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_built_redux/flutter_built_redux.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -void main() { - runApp(BuiltReduxApp()); -} - -class BuiltReduxApp extends StatefulWidget { - final store = Store( - reducerBuilder.build(), - AppState.loading(), - AppActions(), - middleware: [ - createStoreTodosMiddleware(), - ], - ); - - @override - State createState() { - return BuiltReduxAppState(); - } -} - -class BuiltReduxAppState extends State { - Store store; - - @override - void initState() { - store = widget.store; - - store.actions.fetchTodosAction(); - - super.initState(); - } - - @override - Widget build(BuildContext context) { - return ReduxProvider( - store: store, - child: MaterialApp( - onGenerateTitle: (context) => - BuiltReduxLocalizations.of(context).appTitle, - theme: ArchSampleTheme.theme, - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - BuiltReduxLocalizationsDelegate(), - ], - routes: { - ArchSampleRoutes.home: (context) { - return HomeScreen(key: ArchSampleKeys.homeScreen); - }, - ArchSampleRoutes.addTodo: (context) { - return AddTodo(); - }, - }, - ), - ); - } -} diff --git a/built_redux/lib/middleware/store_todos_middleware.dart b/built_redux/lib/middleware/store_todos_middleware.dart deleted file mode 100644 index cac929ee..00000000 --- a/built_redux/lib/middleware/store_todos_middleware.dart +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux/built_redux.dart'; -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/data/todos_repository.dart'; -import 'package:built_redux_sample/models/models.dart'; - -Middleware createStoreTodosMiddleware([ - TodosRepository repository = const TodosRepository(), -]) { - return (MiddlewareBuilder() - ..add(AppActionsNames.fetchTodosAction, createFetchTodos(repository)) - ..add(AppActionsNames.addTodoAction, createSaveTodos(repository)) - ..add(AppActionsNames.clearCompletedAction, - createSaveTodos(repository)) - ..add(AppActionsNames.loadTodosSuccess, - createSaveTodos>(repository)) - ..add(AppActionsNames.deleteTodoAction, - createSaveTodos(repository)) - ..add( - AppActionsNames.toggleAllAction, createSaveTodos(repository)) - ..add(AppActionsNames.updateTodoAction, - createSaveTodos(repository))) - .build(); -} - -MiddlewareHandler createFetchTodos( - TodosRepository repository) { - return (MiddlewareApi api, - ActionHandler next, Action action) { - if (api.state.isLoading) { - repository.loadTodos().then((todos) { - return api.actions.loadTodosSuccess(todos); - }).catchError(api.actions.loadTodosFailure); - } - - next(action); - }; -} - -MiddlewareHandler createSaveTodos( - TodosRepository repository) { - return (MiddlewareApi api, - ActionHandler next, Action action) { - next(action); - - repository.saveTodos(api.state.todos.toList()); - }; -} diff --git a/built_redux/lib/models/app_state.dart b/built_redux/lib/models/app_state.dart deleted file mode 100644 index 09caa3dc..00000000 --- a/built_redux/lib/models/app_state.dart +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library app_state; - -import 'package:built_collection/built_collection.dart'; -import 'package:built_redux_sample/models/app_tab.dart'; -import 'package:built_redux_sample/models/todo.dart'; -import 'package:built_redux_sample/models/visibility_filter.dart'; -import 'package:built_value/built_value.dart'; -import 'package:built_value/serializer.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -part 'app_state.g.dart'; - -abstract class AppState implements Built { - static Serializer get serializer => _$appStateSerializer; - - bool get isLoading; - - BuiltList get todos; - - AppTab get activeTab; - - VisibilityFilter get activeFilter; - - AppState._(); - - factory AppState([void Function(AppStateBuilder b) updates]) => - _$AppState((b) => b - ..isLoading = false - ..todos = ListBuilder([]) - ..activeTab = AppTab.todos - ..activeFilter = VisibilityFilter.all - ..update(updates)); - - factory AppState.loading() => AppState((b) => b..isLoading = true); - - factory AppState.fromTodos(List todos) => - AppState((b) => b..todos = ListBuilder(todos)); - - /// [numCompletedSelector] memoizes and returns the number of complete todos. - @memoized - int get numCompletedSelector => - todos.fold(0, (sum, todo) => todo.complete ? ++sum : sum); - - /// [numActiveSelector] returns and memoizes the number of active todos. - /// Note it is computed using numCompletedSelector. Since `numCompletedSelector` is memoized, this is - /// cheaper than iterating over all todos again by doing todos.fold(0, (sum, todo) => !todo.complete ? ++sum : sum); - @memoized - int get numActiveSelector => todos.length - numCompletedSelector; - - /// [allCompleteSelector] returns and memoizes a boolean value which is true if all todos are complete. - /// Note it is computed using numCompletedSelector. Since `numCompletedSelector` is memoized, this is - /// cheaper than iterating over all todos again by doing todos.every((t) => t.completed); - @memoized - bool get allCompleteSelector => numCompletedSelector == todos.length; - - @memoized - List get filteredTodosSelector => todos.where((todo) { - switch (activeFilter) { - case VisibilityFilter.active: - return !todo.complete; - case VisibilityFilter.completed: - return todo.complete; - case VisibilityFilter.all: - default: - return true; - } - }).toList(); - - Optional todoSelector(String id) { - try { - return Optional.of(todos.firstWhere((todo) => todo.id == id)); - } catch (e) { - return Optional.absent(); - } - } -} diff --git a/built_redux/lib/models/app_state.g.dart b/built_redux/lib/models/app_state.g.dart deleted file mode 100644 index 6b75b07d..00000000 --- a/built_redux/lib/models/app_state.g.dart +++ /dev/null @@ -1,232 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of app_state; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -Serializer _$appStateSerializer = new _$AppStateSerializer(); - -class _$AppStateSerializer implements StructuredSerializer { - @override - final Iterable types = const [AppState, _$AppState]; - @override - final String wireName = 'AppState'; - - @override - Iterable serialize(Serializers serializers, AppState object, - {FullType specifiedType = FullType.unspecified}) { - final result = [ - 'isLoading', - serializers.serialize(object.isLoading, - specifiedType: const FullType(bool)), - 'todos', - serializers.serialize(object.todos, - specifiedType: - const FullType(BuiltList, const [const FullType(Todo)])), - 'activeTab', - serializers.serialize(object.activeTab, - specifiedType: const FullType(AppTab)), - 'activeFilter', - serializers.serialize(object.activeFilter, - specifiedType: const FullType(VisibilityFilter)), - ]; - - return result; - } - - @override - AppState deserialize(Serializers serializers, Iterable serialized, - {FullType specifiedType = FullType.unspecified}) { - final result = new AppStateBuilder(); - - final iterator = serialized.iterator; - while (iterator.moveNext()) { - final key = iterator.current as String; - iterator.moveNext(); - final dynamic value = iterator.current; - switch (key) { - case 'isLoading': - result.isLoading = serializers.deserialize(value, - specifiedType: const FullType(bool)) as bool; - break; - case 'todos': - result.todos.replace(serializers.deserialize(value, - specifiedType: - const FullType(BuiltList, const [const FullType(Todo)])) - as BuiltList); - break; - case 'activeTab': - result.activeTab = serializers.deserialize(value, - specifiedType: const FullType(AppTab)) as AppTab; - break; - case 'activeFilter': - result.activeFilter = serializers.deserialize(value, - specifiedType: const FullType(VisibilityFilter)) - as VisibilityFilter; - break; - } - } - - return result.build(); - } -} - -class _$AppState extends AppState { - @override - final bool isLoading; - @override - final BuiltList todos; - @override - final AppTab activeTab; - @override - final VisibilityFilter activeFilter; - int __numCompletedSelector; - int __numActiveSelector; - bool __allCompleteSelector; - List __filteredTodosSelector; - - factory _$AppState([void Function(AppStateBuilder) updates]) => - (new AppStateBuilder()..update(updates)).build(); - - _$AppState._({this.isLoading, this.todos, this.activeTab, this.activeFilter}) - : super._() { - if (isLoading == null) { - throw new BuiltValueNullFieldError('AppState', 'isLoading'); - } - if (todos == null) { - throw new BuiltValueNullFieldError('AppState', 'todos'); - } - if (activeTab == null) { - throw new BuiltValueNullFieldError('AppState', 'activeTab'); - } - if (activeFilter == null) { - throw new BuiltValueNullFieldError('AppState', 'activeFilter'); - } - } - - @override - int get numCompletedSelector => - __numCompletedSelector ??= super.numCompletedSelector; - - @override - int get numActiveSelector => __numActiveSelector ??= super.numActiveSelector; - - @override - bool get allCompleteSelector => - __allCompleteSelector ??= super.allCompleteSelector; - - @override - List get filteredTodosSelector => - __filteredTodosSelector ??= super.filteredTodosSelector; - - @override - AppState rebuild(void Function(AppStateBuilder) updates) => - (toBuilder()..update(updates)).build(); - - @override - AppStateBuilder toBuilder() => new AppStateBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - return other is AppState && - isLoading == other.isLoading && - todos == other.todos && - activeTab == other.activeTab && - activeFilter == other.activeFilter; - } - - @override - int get hashCode { - return $jf($jc( - $jc($jc($jc(0, isLoading.hashCode), todos.hashCode), - activeTab.hashCode), - activeFilter.hashCode)); - } - - @override - String toString() { - return (newBuiltValueToStringHelper('AppState') - ..add('isLoading', isLoading) - ..add('todos', todos) - ..add('activeTab', activeTab) - ..add('activeFilter', activeFilter)) - .toString(); - } -} - -class AppStateBuilder implements Builder { - _$AppState _$v; - - bool _isLoading; - bool get isLoading => _$this._isLoading; - set isLoading(bool isLoading) => _$this._isLoading = isLoading; - - ListBuilder _todos; - ListBuilder get todos => _$this._todos ??= new ListBuilder(); - set todos(ListBuilder todos) => _$this._todos = todos; - - AppTab _activeTab; - AppTab get activeTab => _$this._activeTab; - set activeTab(AppTab activeTab) => _$this._activeTab = activeTab; - - VisibilityFilter _activeFilter; - VisibilityFilter get activeFilter => _$this._activeFilter; - set activeFilter(VisibilityFilter activeFilter) => - _$this._activeFilter = activeFilter; - - AppStateBuilder(); - - AppStateBuilder get _$this { - if (_$v != null) { - _isLoading = _$v.isLoading; - _todos = _$v.todos?.toBuilder(); - _activeTab = _$v.activeTab; - _activeFilter = _$v.activeFilter; - _$v = null; - } - return this; - } - - @override - void replace(AppState other) { - if (other == null) { - throw new ArgumentError.notNull('other'); - } - _$v = other as _$AppState; - } - - @override - void update(void Function(AppStateBuilder) updates) { - if (updates != null) updates(this); - } - - @override - _$AppState build() { - _$AppState _$result; - try { - _$result = _$v ?? - new _$AppState._( - isLoading: isLoading, - todos: todos.build(), - activeTab: activeTab, - activeFilter: activeFilter); - } catch (_) { - String _$failedField; - try { - _$failedField = 'todos'; - todos.build(); - } catch (e) { - throw new BuiltValueNestedFieldError( - 'AppState', _$failedField, e.toString()); - } - rethrow; - } - replace(_$result); - return _$result; - } -} - -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new diff --git a/built_redux/lib/models/app_tab.dart b/built_redux/lib/models/app_tab.dart deleted file mode 100644 index 4d680237..00000000 --- a/built_redux/lib/models/app_tab.dart +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library app_tab; - -import 'package:built_collection/built_collection.dart'; -import 'package:built_value/built_value.dart'; -import 'package:built_value/serializer.dart'; - -part 'app_tab.g.dart'; - -class AppTab extends EnumClass { - static Serializer get serializer => _$appTabSerializer; - - static const AppTab todos = _$todos; - static const AppTab stats = _$stats; - - const AppTab._(String name) : super(name); - - static BuiltSet get values => _$appTabValues; - - static AppTab valueOf(String name) => _$appTabValueOf(name); - - static AppTab fromIndex(int index) { - switch (index) { - case 1: - return AppTab.stats; - default: - return AppTab.todos; - } - } - - static int toIndex(AppTab tab) { - switch (tab) { - case AppTab.stats: - return 1; - default: - return 0; - } - } -} diff --git a/built_redux/lib/models/app_tab.g.dart b/built_redux/lib/models/app_tab.g.dart deleted file mode 100644 index dc9598d7..00000000 --- a/built_redux/lib/models/app_tab.g.dart +++ /dev/null @@ -1,47 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of app_tab; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -const AppTab _$todos = const AppTab._('todos'); -const AppTab _$stats = const AppTab._('stats'); - -AppTab _$appTabValueOf(String name) { - switch (name) { - case 'todos': - return _$todos; - case 'stats': - return _$stats; - default: - throw new ArgumentError(name); - } -} - -final BuiltSet _$appTabValues = new BuiltSet(const [ - _$todos, - _$stats, -]); - -Serializer _$appTabSerializer = new _$AppTabSerializer(); - -class _$AppTabSerializer implements PrimitiveSerializer { - @override - final Iterable types = const [AppTab]; - @override - final String wireName = 'AppTab'; - - @override - Object serialize(Serializers serializers, AppTab object, - {FullType specifiedType = FullType.unspecified}) => - object.name; - - @override - AppTab deserialize(Serializers serializers, Object serialized, - {FullType specifiedType = FullType.unspecified}) => - AppTab.valueOf(serialized as String); -} - -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new diff --git a/built_redux/lib/models/extra_actions.dart b/built_redux/lib/models/extra_actions.dart deleted file mode 100644 index 5da0bbbd..00000000 --- a/built_redux/lib/models/extra_actions.dart +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library extra_actions; - -import 'package:built_collection/built_collection.dart'; -import 'package:built_value/built_value.dart'; -import 'package:built_value/serializer.dart'; - -part 'extra_actions.g.dart'; - -class ExtraAction extends EnumClass { - static Serializer get serializer => _$extraActionSerializer; - - static const ExtraAction toggleAllComplete = _$toggleAllComplete; - static const ExtraAction clearCompleted = _$clearCompleted; - - const ExtraAction._(String name) : super(name); - - static BuiltSet get values => _$extraActionValues; - - static ExtraAction valueOf(String name) => _$extraActionValueOf(name); -} diff --git a/built_redux/lib/models/extra_actions.g.dart b/built_redux/lib/models/extra_actions.g.dart deleted file mode 100644 index 309b36b8..00000000 --- a/built_redux/lib/models/extra_actions.g.dart +++ /dev/null @@ -1,49 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of extra_actions; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -const ExtraAction _$toggleAllComplete = - const ExtraAction._('toggleAllComplete'); -const ExtraAction _$clearCompleted = const ExtraAction._('clearCompleted'); - -ExtraAction _$extraActionValueOf(String name) { - switch (name) { - case 'toggleAllComplete': - return _$toggleAllComplete; - case 'clearCompleted': - return _$clearCompleted; - default: - throw new ArgumentError(name); - } -} - -final BuiltSet _$extraActionValues = - new BuiltSet(const [ - _$toggleAllComplete, - _$clearCompleted, -]); - -Serializer _$extraActionSerializer = new _$ExtraActionSerializer(); - -class _$ExtraActionSerializer implements PrimitiveSerializer { - @override - final Iterable types = const [ExtraAction]; - @override - final String wireName = 'ExtraAction'; - - @override - Object serialize(Serializers serializers, ExtraAction object, - {FullType specifiedType = FullType.unspecified}) => - object.name; - - @override - ExtraAction deserialize(Serializers serializers, Object serialized, - {FullType specifiedType = FullType.unspecified}) => - ExtraAction.valueOf(serialized as String); -} - -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new diff --git a/built_redux/lib/models/models.dart b/built_redux/lib/models/models.dart deleted file mode 100644 index 5541a539..00000000 --- a/built_redux/lib/models/models.dart +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library models; - -export 'app_state.dart'; -export 'app_tab.dart'; -export 'extra_actions.dart'; -export 'todo.dart'; -export 'visibility_filter.dart'; diff --git a/built_redux/lib/models/serializers.dart b/built_redux/lib/models/serializers.dart deleted file mode 100644 index 242371fc..00000000 --- a/built_redux/lib/models/serializers.dart +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library serializers; - -import 'package:built_collection/built_collection.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_value/serializer.dart'; - -part 'serializers.g.dart'; - -@SerializersFor([ - AppTab, - ExtraAction, - VisibilityFilter, - AppState, - Todo, -]) -final Serializers serializers = _$serializers; diff --git a/built_redux/lib/models/serializers.g.dart b/built_redux/lib/models/serializers.g.dart deleted file mode 100644 index 0eb437ee..00000000 --- a/built_redux/lib/models/serializers.g.dart +++ /dev/null @@ -1,20 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of serializers; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -Serializers _$serializers = (new Serializers().toBuilder() - ..add(AppState.serializer) - ..add(AppTab.serializer) - ..add(ExtraAction.serializer) - ..add(Todo.serializer) - ..add(VisibilityFilter.serializer) - ..addBuilderFactory( - const FullType(BuiltList, const [const FullType(Todo)]), - () => new ListBuilder())) - .build(); - -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new diff --git a/built_redux/lib/models/todo.dart b/built_redux/lib/models/todo.dart deleted file mode 100644 index 750582cf..00000000 --- a/built_redux/lib/models/todo.dart +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library todo; - -import 'package:built_value/built_value.dart'; -import 'package:built_value/serializer.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -part 'todo.g.dart'; - -abstract class Todo implements Built { - static Serializer get serializer => _$todoSerializer; - - bool get complete; - - String get id; - - String get note; - - String get task; - - Todo._(); - - factory Todo(String task) { - return _$Todo._( - task: task, - complete: false, - note: '', - id: Uuid().generateV4(), - ); - } - - factory Todo.builder([void Function(TodoBuilder b) updates]) { - final builder = TodoBuilder() - ..id = Uuid().generateV4() - ..complete = false - ..note = '' - ..update(updates); - - return builder.build(); - } -} diff --git a/built_redux/lib/models/todo.g.dart b/built_redux/lib/models/todo.g.dart deleted file mode 100644 index d59bf4b1..00000000 --- a/built_redux/lib/models/todo.g.dart +++ /dev/null @@ -1,186 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of todo; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -Serializer _$todoSerializer = new _$TodoSerializer(); - -class _$TodoSerializer implements StructuredSerializer { - @override - final Iterable types = const [Todo, _$Todo]; - @override - final String wireName = 'Todo'; - - @override - Iterable serialize(Serializers serializers, Todo object, - {FullType specifiedType = FullType.unspecified}) { - final result = [ - 'complete', - serializers.serialize(object.complete, - specifiedType: const FullType(bool)), - 'id', - serializers.serialize(object.id, specifiedType: const FullType(String)), - 'note', - serializers.serialize(object.note, specifiedType: const FullType(String)), - 'task', - serializers.serialize(object.task, specifiedType: const FullType(String)), - ]; - - return result; - } - - @override - Todo deserialize(Serializers serializers, Iterable serialized, - {FullType specifiedType = FullType.unspecified}) { - final result = new TodoBuilder(); - - final iterator = serialized.iterator; - while (iterator.moveNext()) { - final key = iterator.current as String; - iterator.moveNext(); - final dynamic value = iterator.current; - switch (key) { - case 'complete': - result.complete = serializers.deserialize(value, - specifiedType: const FullType(bool)) as bool; - break; - case 'id': - result.id = serializers.deserialize(value, - specifiedType: const FullType(String)) as String; - break; - case 'note': - result.note = serializers.deserialize(value, - specifiedType: const FullType(String)) as String; - break; - case 'task': - result.task = serializers.deserialize(value, - specifiedType: const FullType(String)) as String; - break; - } - } - - return result.build(); - } -} - -class _$Todo extends Todo { - @override - final bool complete; - @override - final String id; - @override - final String note; - @override - final String task; - - factory _$Todo([void Function(TodoBuilder) updates]) => - (new TodoBuilder()..update(updates)).build(); - - _$Todo._({this.complete, this.id, this.note, this.task}) : super._() { - if (complete == null) { - throw new BuiltValueNullFieldError('Todo', 'complete'); - } - if (id == null) { - throw new BuiltValueNullFieldError('Todo', 'id'); - } - if (note == null) { - throw new BuiltValueNullFieldError('Todo', 'note'); - } - if (task == null) { - throw new BuiltValueNullFieldError('Todo', 'task'); - } - } - - @override - Todo rebuild(void Function(TodoBuilder) updates) => - (toBuilder()..update(updates)).build(); - - @override - TodoBuilder toBuilder() => new TodoBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - return other is Todo && - complete == other.complete && - id == other.id && - note == other.note && - task == other.task; - } - - @override - int get hashCode { - return $jf($jc( - $jc($jc($jc(0, complete.hashCode), id.hashCode), note.hashCode), - task.hashCode)); - } - - @override - String toString() { - return (newBuiltValueToStringHelper('Todo') - ..add('complete', complete) - ..add('id', id) - ..add('note', note) - ..add('task', task)) - .toString(); - } -} - -class TodoBuilder implements Builder { - _$Todo _$v; - - bool _complete; - bool get complete => _$this._complete; - set complete(bool complete) => _$this._complete = complete; - - String _id; - String get id => _$this._id; - set id(String id) => _$this._id = id; - - String _note; - String get note => _$this._note; - set note(String note) => _$this._note = note; - - String _task; - String get task => _$this._task; - set task(String task) => _$this._task = task; - - TodoBuilder(); - - TodoBuilder get _$this { - if (_$v != null) { - _complete = _$v.complete; - _id = _$v.id; - _note = _$v.note; - _task = _$v.task; - _$v = null; - } - return this; - } - - @override - void replace(Todo other) { - if (other == null) { - throw new ArgumentError.notNull('other'); - } - _$v = other as _$Todo; - } - - @override - void update(void Function(TodoBuilder) updates) { - if (updates != null) updates(this); - } - - @override - _$Todo build() { - final _$result = - _$v ?? new _$Todo._(complete: complete, id: id, note: note, task: task); - replace(_$result); - return _$result; - } -} - -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new diff --git a/built_redux/lib/models/visibility_filter.dart b/built_redux/lib/models/visibility_filter.dart deleted file mode 100644 index 8aa22376..00000000 --- a/built_redux/lib/models/visibility_filter.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library visibility_filter; - -import 'package:built_collection/built_collection.dart'; -import 'package:built_value/built_value.dart'; -import 'package:built_value/serializer.dart'; - -part 'visibility_filter.g.dart'; - -class VisibilityFilter extends EnumClass { - static Serializer get serializer => - _$visibilityFilterSerializer; - - static const VisibilityFilter all = _$all; - static const VisibilityFilter active = _$active; - static const VisibilityFilter completed = _$completed; - - const VisibilityFilter._(String name) : super(name); - - static BuiltSet get values => _$visibilityFilterValues; - - static VisibilityFilter valueOf(String name) => - _$visibilityFilterValueOf(name); -} diff --git a/built_redux/lib/models/visibility_filter.g.dart b/built_redux/lib/models/visibility_filter.g.dart deleted file mode 100644 index d8bab605..00000000 --- a/built_redux/lib/models/visibility_filter.g.dart +++ /dev/null @@ -1,54 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of visibility_filter; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -const VisibilityFilter _$all = const VisibilityFilter._('all'); -const VisibilityFilter _$active = const VisibilityFilter._('active'); -const VisibilityFilter _$completed = const VisibilityFilter._('completed'); - -VisibilityFilter _$visibilityFilterValueOf(String name) { - switch (name) { - case 'all': - return _$all; - case 'active': - return _$active; - case 'completed': - return _$completed; - default: - throw new ArgumentError(name); - } -} - -final BuiltSet _$visibilityFilterValues = - new BuiltSet(const [ - _$all, - _$active, - _$completed, -]); - -Serializer _$visibilityFilterSerializer = - new _$VisibilityFilterSerializer(); - -class _$VisibilityFilterSerializer - implements PrimitiveSerializer { - @override - final Iterable types = const [VisibilityFilter]; - @override - final String wireName = 'VisibilityFilter'; - - @override - Object serialize(Serializers serializers, VisibilityFilter object, - {FullType specifiedType = FullType.unspecified}) => - object.name; - - @override - VisibilityFilter deserialize(Serializers serializers, Object serialized, - {FullType specifiedType = FullType.unspecified}) => - VisibilityFilter.valueOf(serialized as String); -} - -// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new diff --git a/built_redux/lib/presentation/add_edit_screen.dart b/built_redux/lib/presentation/add_edit_screen.dart deleted file mode 100644 index 0f5b9b87..00000000 --- a/built_redux/lib/presentation/add_edit_screen.dart +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/models/models.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -typedef OnSaveCallback = void Function(String task, String note); - -class AddEditScreen extends StatefulWidget { - final bool isEditing; - final Function(String task, String note) onSave; - final Todo todo; - - AddEditScreen( - {Key key, @required this.onSave, @required this.isEditing, this.todo}) - : super(key: key ?? ArchSampleKeys.addTodoScreen); - @override - _AddEditScreenState createState() => _AddEditScreenState(); -} - -class _AddEditScreenState extends State { - static final GlobalKey _formKey = GlobalKey(); - - String _task; - String _note; - - bool get isEditing => widget.isEditing; - - @override - Widget build(BuildContext context) { - final localizations = ArchSampleLocalizations.of(context); - final textTheme = Theme.of(context).textTheme; - - return Scaffold( - appBar: AppBar( - title: Text( - isEditing ? localizations.editTodo : localizations.addTodo, - ), - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: Form( - key: _formKey, - child: ListView( - children: [ - TextFormField( - initialValue: isEditing ? widget.todo.task : '', - key: ArchSampleKeys.taskField, - autofocus: !isEditing, - style: textTheme.headline, - decoration: InputDecoration( - hintText: localizations.newTodoHint, - ), - validator: (val) { - return val.trim().isEmpty - ? localizations.emptyTodoError - : null; - }, - onSaved: (value) => _task = value, - ), - TextFormField( - initialValue: isEditing ? widget.todo.note : '', - key: ArchSampleKeys.noteField, - maxLines: 10, - style: textTheme.subhead, - decoration: InputDecoration( - hintText: localizations.notesHint, - ), - onSaved: (value) => _note = value, - ) - ], - ), - ), - ), - floatingActionButton: FloatingActionButton( - key: - isEditing ? ArchSampleKeys.saveTodoFab : ArchSampleKeys.saveNewTodo, - tooltip: isEditing ? localizations.saveChanges : localizations.addTodo, - child: Icon(isEditing ? Icons.check : Icons.add), - onPressed: () { - if (_formKey.currentState.validate()) { - _formKey.currentState.save(); - widget.onSave(_task, _note); - - Navigator.pop(context); - } - }, - ), - ); - } -} diff --git a/built_redux/lib/presentation/details_screen.dart b/built_redux/lib/presentation/details_screen.dart deleted file mode 100644 index e2bc3143..00000000 --- a/built_redux/lib/presentation/details_screen.dart +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/containers/edit_todo.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class DetailsScreen extends StatelessWidget { - final Todo todo; - final Function onDelete; - final Function(bool) toggleCompleted; - - DetailsScreen({ - Key key, - @required this.todo, - @required this.onDelete, - @required this.toggleCompleted, - }) : super(key: ArchSampleKeys.todoDetailsScreen); - - @override - Widget build(BuildContext context) { - final localizations = ArchSampleLocalizations.of(context); - - return Scaffold( - appBar: AppBar( - title: Text(localizations.todoDetails), - actions: [ - IconButton( - tooltip: localizations.deleteTodo, - icon: Icon(Icons.delete), - key: ArchSampleKeys.deleteTodoButton, - onPressed: () { - onDelete(); - Navigator.pop(context, todo); - }, - ) - ], - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: ListView( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(right: 8.0), - child: Checkbox( - key: ArchSampleKeys.detailsTodoItemCheckbox, - value: todo.complete, - onChanged: toggleCompleted, - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), - child: Text( - todo.task, - key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, - ), - ), - Text( - todo.note, - key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) - ], - ), - ), - ], - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - key: ArchSampleKeys.editTodoFab, - tooltip: localizations.editTodo, - child: Icon(Icons.edit), - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) { - return EditTodo( - todo: todo, - ); - }, - ), - ); - }, - ), - ); - } -} diff --git a/built_redux/lib/presentation/extra_actions_button.dart b/built_redux/lib/presentation/extra_actions_button.dart deleted file mode 100644 index ee08fc23..00000000 --- a/built_redux/lib/presentation/extra_actions_button.dart +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/models/models.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class ExtraActionsButton extends StatelessWidget { - final PopupMenuItemSelected onSelected; - final bool allComplete; - - ExtraActionsButton({ - this.onSelected, - this.allComplete = false, - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return PopupMenuButton( - key: ArchSampleKeys.extraActionsButton, - onSelected: onSelected, - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - key: ArchSampleKeys.toggleAll, - value: ExtraAction.toggleAllComplete, - child: Text(allComplete - ? ArchSampleLocalizations.of(context).markAllIncomplete - : ArchSampleLocalizations.of(context).markAllComplete), - ), - PopupMenuItem( - key: ArchSampleKeys.clearCompleted, - value: ExtraAction.clearCompleted, - child: Text(ArchSampleLocalizations.of(context).clearCompleted), - ), - ], - ); - } -} diff --git a/built_redux/lib/presentation/filter_button.dart b/built_redux/lib/presentation/filter_button.dart deleted file mode 100644 index dc2b5e59..00000000 --- a/built_redux/lib/presentation/filter_button.dart +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/models/models.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class FilterButton extends StatelessWidget { - final PopupMenuItemSelected onSelected; - final VisibilityFilter activeFilter; - final bool visible; - - FilterButton({this.onSelected, this.activeFilter, this.visible, Key key}) - : super(key: key); - - @override - Widget build(BuildContext context) { - final defaultStyle = Theme.of(context).textTheme.body1; - final activeStyle = Theme.of(context) - .textTheme - .body1 - .copyWith(color: Theme.of(context).accentColor); - - return AnimatedOpacity( - opacity: visible ? 1.0 : 0.0, - duration: Duration(milliseconds: 150), - child: PopupMenuButton( - key: ArchSampleKeys.filterButton, - tooltip: ArchSampleLocalizations.of(context).filterTodos, - onSelected: onSelected, - itemBuilder: (BuildContext context) => - >[ - PopupMenuItem( - value: VisibilityFilter.all, - child: Text( - ArchSampleLocalizations.of(context).showAll, - key: ArchSampleKeys.allFilter, - style: activeFilter == VisibilityFilter.all - ? activeStyle - : defaultStyle, - ), - ), - PopupMenuItem( - value: VisibilityFilter.active, - child: Text( - ArchSampleLocalizations.of(context).showActive, - key: ArchSampleKeys.activeFilter, - style: activeFilter == VisibilityFilter.active - ? activeStyle - : defaultStyle, - ), - ), - PopupMenuItem( - value: VisibilityFilter.completed, - child: Text( - ArchSampleLocalizations.of(context).showCompleted, - key: ArchSampleKeys.completedFilter, - style: activeFilter == VisibilityFilter.completed - ? activeStyle - : defaultStyle, - ), - ), - ], - icon: Icon(Icons.filter_list), - ), - ); - } -} diff --git a/built_redux/lib/presentation/home_screen.dart b/built_redux/lib/presentation/home_screen.dart deleted file mode 100644 index 032e1ed9..00000000 --- a/built_redux/lib/presentation/home_screen.dart +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/containers/action_selector.dart'; -import 'package:built_redux_sample/containers/active_tab.dart'; -import 'package:built_redux_sample/containers/filter_selector.dart'; -import 'package:built_redux_sample/containers/filtered_todos.dart'; -import 'package:built_redux_sample/containers/stats.dart'; -import 'package:built_redux_sample/containers/tab_selector.dart'; -import 'package:built_redux_sample/localization.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_redux_sample/presentation/filter_button.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class HomeScreen extends StatelessWidget { - HomeScreen({Key key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return ActiveTab( - builder: (BuildContext context, AppTab activeTab) { - return Scaffold( - appBar: AppBar( - title: Text(BuiltReduxLocalizations.of(context).appTitle), - actions: [ - FilterSelector( - builder: (context, vm) { - return FilterButton( - visible: activeTab == AppTab.todos, - activeFilter: vm.activeFilter, - onSelected: vm.onFilterSelected, - ); - }, - ), - ExtraActionSelector() - ], - ), - body: activeTab == AppTab.todos ? FilteredTodos() : Stats(), - floatingActionButton: FloatingActionButton( - key: ArchSampleKeys.addTodoFab, - onPressed: () { - Navigator.pushNamed(context, ArchSampleRoutes.addTodo); - }, - child: Icon(Icons.add), - tooltip: ArchSampleLocalizations.of(context).addTodo, - ), - bottomNavigationBar: TabSelector(), - ); - }, - ); - } -} diff --git a/built_redux/lib/presentation/stats_counter.dart b/built_redux/lib/presentation/stats_counter.dart deleted file mode 100644 index 4218058b..00000000 --- a/built_redux/lib/presentation/stats_counter.dart +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/containers/app_loading.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class StatsCounter extends StatelessWidget { - final int numActive; - final int numCompleted; - - StatsCounter({ - @required this.numActive, - @required this.numCompleted, - }); - - @override - Widget build(BuildContext context) { - return AppLoading(builder: (context, loading) { - return loading - ? Center( - key: ArchSampleKeys.statsLoading, - child: CircularProgressIndicator( - key: ArchSampleKeys.statsLoading, - )) - : Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '$numCompleted', - key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '$numActive', - key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, - ), - ) - ], - ), - ); - }); - } -} diff --git a/built_redux/lib/presentation/todo_item.dart b/built_redux/lib/presentation/todo_item.dart deleted file mode 100644 index a1d9c07c..00000000 --- a/built_redux/lib/presentation/todo_item.dart +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/models/models.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class TodoItem extends StatelessWidget { - final DismissDirectionCallback onDismissed; - final GestureTapCallback onTap; - final ValueChanged onCheckboxChanged; - final Todo todo; - - TodoItem({ - @required this.onDismissed, - @required this.onTap, - @required this.onCheckboxChanged, - @required this.todo, - }) : super(key: ArchSampleKeys.todoItem(todo.id)); - - @override - Widget build(BuildContext context) { - return Dismissible( - key: Key(todo.id), - onDismissed: onDismissed, - child: ListTile( - onTap: onTap, - leading: Checkbox( - key: ArchSampleKeys.todoItemCheckbox(todo.id), - value: todo.complete, - onChanged: onCheckboxChanged, - ), - title: Text( - todo.task, - key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, - ), - subtitle: Text( - todo.note, - key: ArchSampleKeys.todoItemNote(todo.id), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, - ), - ), - ); - } -} diff --git a/built_redux/lib/presentation/todo_list.dart b/built_redux/lib/presentation/todo_list.dart deleted file mode 100644 index a833ef1e..00000000 --- a/built_redux/lib/presentation/todo_list.dart +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/containers/app_loading.dart'; -import 'package:built_redux_sample/containers/todo_details.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_redux_sample/presentation/todo_item.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class TodoList extends StatelessWidget { - final List todos; - final Function(Todo, bool) onCheckboxChanged; - final Function(Todo) onRemove; - final Function(Todo) onUndoRemove; - - TodoList({ - @required this.todos, - @required this.onCheckboxChanged, - @required this.onRemove, - @required this.onUndoRemove, - }) : super(key: ArchSampleKeys.todoList); - - @override - Widget build(BuildContext context) { - return AppLoading(builder: (context, loading) { - return loading - ? Center( - key: ArchSampleKeys.todosLoading, - child: CircularProgressIndicator( - key: ArchSampleKeys.statsLoading, - )) - : Container( - child: ListView.builder( - key: ArchSampleKeys.todoList, - itemCount: todos.length, - itemBuilder: (BuildContext context, int index) { - final todo = todos[index]; - - return TodoItem( - todo: todo, - onDismissed: (direction) { - _removeTodo(context, todo); - }, - onTap: () => _onTodoTap(context, todo), - onCheckboxChanged: (complete) { - onCheckboxChanged(todo, complete); - }, - ); - }, - ), - ); - }); - } - - void _removeTodo(BuildContext context, Todo todo) { - onRemove(todo); - - Scaffold.of(context).showSnackBar(SnackBar( - key: ArchSampleKeys.snackbar, - duration: Duration(seconds: 2), - content: Text( - ArchSampleLocalizations.of(context).todoDeleted(todo.task), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - action: SnackBarAction( - label: ArchSampleLocalizations.of(context).undo, - onPressed: () => onUndoRemove(todo), - ))); - } - - void _onTodoTap(BuildContext context, Todo todo) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) { - return TodoDetails( - id: todo.id, - ); - }, - ), - ).then((removedTodo) { - if (removedTodo != null) { - Scaffold.of(context).showSnackBar( - SnackBar( - key: ArchSampleKeys.snackbar, - duration: Duration(seconds: 2), - content: Text( - ArchSampleLocalizations.of(context).todoDeleted(todo.task), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - action: SnackBarAction( - label: ArchSampleLocalizations.of(context).undo, - onPressed: () { - onUndoRemove(todo); - }, - ), - ), - ); - } - }); - } -} diff --git a/built_redux/lib/reducers/reducers.dart b/built_redux/lib/reducers/reducers.dart deleted file mode 100644 index e2e04662..00000000 --- a/built_redux/lib/reducers/reducers.dart +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux/built_redux.dart'; -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/models/models.dart'; - -var reducerBuilder = ReducerBuilder() - ..add(AppActionsNames.addTodoAction, addTodo) - ..add(AppActionsNames.clearCompletedAction, clearCompleted) - ..add(AppActionsNames.deleteTodoAction, deleteTodo) - ..add(AppActionsNames.toggleAllAction, toggleAll) - ..add(AppActionsNames.updateFilterAction, updateFilter) - ..add(AppActionsNames.updateTabAction, updateTab) - ..add(AppActionsNames.updateTodoAction, updateTodo) - ..add(AppActionsNames.loadTodosSuccess, todosLoaded) - ..add(AppActionsNames.loadTodosFailure, todosLoadFailed); - -void addTodo(AppState state, Action action, AppStateBuilder builder) { - builder.todos.add(action.payload); -} - -void clearCompleted( - AppState state, Action action, AppStateBuilder builder) { - builder.todos.where((todo) => !todo.complete); -} - -void deleteTodo( - AppState state, Action action, AppStateBuilder builder) { - builder.todos.where((todo) => todo.id != action.payload); -} - -void toggleAll(AppState state, Action action, AppStateBuilder builder) { - final allComplete = state.allCompleteSelector; - builder.todos.map((todo) => todo.rebuild((b) => b..complete = !allComplete)); -} - -void updateFilter( - AppState state, Action action, AppStateBuilder builder) { - builder.activeFilter = action.payload; -} - -void updateTab(AppState state, Action action, AppStateBuilder builder) { - builder.activeTab = action.payload; -} - -void todosLoaded( - AppState state, Action> action, AppStateBuilder builder) { - builder - ..isLoading = false - ..todos.addAll(action.payload); -} - -void todosLoadFailed( - AppState state, Action action, AppStateBuilder builder) { - builder - ..isLoading = false - ..todos.clear(); -} - -void updateTodo(AppState state, Action action, - AppStateBuilder builder) { - builder.todos.map((todo) => - todo.id == action.payload.id ? action.payload.updatedTodo : todo); -} diff --git a/built_redux/pubspec.yaml b/built_redux/pubspec.yaml deleted file mode 100644 index b0159388..00000000 --- a/built_redux/pubspec.yaml +++ /dev/null @@ -1,83 +0,0 @@ -name: built_redux_sample -description: A new Flutter project. - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 - -environment: - sdk: ">=2.1.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - flutter_built_redux: - built_redux: - built_value: - built_collection: - todos_app_core: - path: ../todos_app_core - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_driver: - sdk: flutter - test: - build: - build_runner: - built_value_generator: - source_gen: - mockito: - integration_tests: - path: ../integration_tests - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/built_redux/test/all_tests.dart b/built_redux/test/all_tests.dart deleted file mode 100644 index 45d9ff51..00000000 --- a/built_redux/test/all_tests.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'app_state_test.dart' as app_state; -import 'file_storage_test.dart' as file_storage; -import 'middleware_test.dart' as middleware; -import 'reducer_test.dart' as reducer; -import 'todos_repository_test.dart' as todos_repository; - -void main() { - app_state.main(); - file_storage.main(); - middleware.main(); - reducer.main(); - todos_repository.main(); -} diff --git a/built_redux/test/app_state_test.dart b/built_redux/test/app_state_test.dart deleted file mode 100644 index 52b9d095..00000000 --- a/built_redux/test/app_state_test.dart +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux_sample/models/models.dart'; -import 'package:test/test.dart'; - -void main() { - group('Selector Tests', () { - test('should calculate the number of active todos', () { - final state = AppState.fromTodos([ - Todo('a'), - Todo('b'), - Todo.builder( - (b) => b - ..task = 'c' - ..complete = true, - ), - ]); - - expect(state.numActiveSelector, 2); - }); - - test('should calculate the number of completed todos', () { - final state = AppState.fromTodos([ - Todo('a'), - Todo('b'), - Todo.builder( - (b) => b - ..task = 'c' - ..complete = true, - ), - ]); - - expect(state.numCompletedSelector, 1); - }); - - test('should return all todos if the VisibilityFilter is all', () { - final todos = [ - Todo('a'), - Todo('b'), - Todo.builder( - (b) => b - ..task = 'c' - ..complete = true, - ), - ]; - final state = AppState.fromTodos(todos); - expect(state.activeFilter, VisibilityFilter.all); - expect(state.filteredTodosSelector, todos); - }); - - test('should return active todos if the VisibilityFilter is active', () { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo.builder( - (b) => b - ..task = 'c' - ..complete = true, - ); - final todos = [ - todo1, - todo2, - todo3, - ]; - final state = AppState.fromTodos(todos) - .rebuild((b) => b.activeFilter = VisibilityFilter.active); - - expect(state.filteredTodosSelector, [todo1, todo2]); - }); - - test('should return completed todos if the VisibilityFilter is completed', - () { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo.builder( - (b) => b - ..task = 'c' - ..complete = true, - ); - final todos = [ - todo1, - todo2, - todo3, - ]; - final state = AppState.fromTodos(todos) - .rebuild((b) => b.activeFilter = VisibilityFilter.completed); - - expect(state.filteredTodosSelector, [todo3]); - }); - }); -} diff --git a/built_redux/test/file_storage_test.dart b/built_redux/test/file_storage_test.dart deleted file mode 100644 index 48328e22..00000000 --- a/built_redux/test/file_storage_test.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:io'; - -import 'package:built_redux_sample/data/file_storage.dart'; -import 'package:built_redux_sample/models/todo.dart'; -import 'package:test/test.dart'; - -void main() { - group('FileStorage', () { - final todos = [Todo('Yep')]; - final directory = Directory.systemTemp.createTemp('__storage_test__'); - final storage = FileStorage( - '_test_tag_', - () => directory, - ); - - tearDownAll(() async { - final tempDirectory = await directory; - - tempDirectory.deleteSync(recursive: true); - }); - - test('Should persist TodoEntities to disk', () async { - final file = await storage.saveTodos(todos); - - expect(file.existsSync(), isTrue); - }); - - test('Should load TodoEntities from disk', () async { - final loadedTodos = await storage.loadTodos(); - - expect(loadedTodos, todos); - }); - }); -} diff --git a/built_redux/test/middleware_test.dart b/built_redux/test/middleware_test.dart deleted file mode 100644 index 687acacc..00000000 --- a/built_redux/test/middleware_test.dart +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:built_redux/built_redux.dart'; -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/data/todos_repository.dart'; -import 'package:built_redux_sample/middleware/store_todos_middleware.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_redux_sample/reducers/reducers.dart'; -import 'package:mockito/mockito.dart'; -import 'package:test/test.dart'; - -/// We create two Mocks for our Web Service and File Storage. We will use these -/// mock classes to verify the behavior of the TodosService. -class MockTodosService extends Mock implements TodosRepository {} - -void main() { - group('TodosMiddleware', () { - test( - 'should load todos when the app dispatches a fetch action and the app is loading', - () { - final service = MockTodosService(); - final middleware = createStoreTodosMiddleware(service); - final store = Store( - reducerBuilder.build(), - AppState.loading(), - AppActions(), - middleware: [middleware], - ); - final todos = [Todo('Task')]; - - // We'll use our mock throughout the tests to set certain conditions. In - // this first test, we want to mock out our file storage to return a - // list of Todos that we define here in our test! - when(service.loadTodos()).thenAnswer((_) => Future.value(todos)); - - store.actions.fetchTodosAction(); - - verify(service.loadTodos()); - }); - - test( - 'should not load todos when the app dispatches a fetch action and the app is not loading', - () { - final service = MockTodosService(); - final middleware = createStoreTodosMiddleware(service); - final store = Store( - reducerBuilder.build(), - AppState(), - AppActions(), - middleware: [middleware], - ); - final todos = [Todo('Task')]; - - // We'll use our mock throughout the tests to set certain conditions. In - // this first test, we want to mock out our file storage to return a - // list of Todos that we define here in our test! - when(service.loadTodos()).thenAnswer((_) => Future.value(todos)); - - store.actions.fetchTodosAction(); - - verifyNever(service.loadTodos()); - }); - - test('should save todos on all action that update the todo', () { - final service = MockTodosService(); - final middleware = createStoreTodosMiddleware(service); - final store = Store( - reducerBuilder.build(), - AppState(), - AppActions(), - middleware: [middleware], - ); - final todos = [Todo('Task')]; - - when(service.saveTodos(todos)).thenAnswer((_) => Future.value(todos)); - - // Dispatch all actions that update our Todos. We expect each to - // trigger a call to our Storage Service. - store.actions.addTodoAction(Todo('Wat')); - store.actions.clearCompletedAction(); - store.actions.deleteTodoAction(''); - store.actions.toggleAllAction(); - store.actions.updateTodoAction(UpdateTodoActionPayload( - '', - Todo('Update'), - )); - - verify(service.saveTodos(any)).called(5); - }); - }); -} diff --git a/built_redux/test/reducer_test.dart b/built_redux/test/reducer_test.dart deleted file mode 100644 index 668d5498..00000000 --- a/built_redux/test/reducer_test.dart +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:built_redux/built_redux.dart'; -import 'package:built_redux_sample/actions/actions.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:built_redux_sample/reducers/reducers.dart'; -import 'package:test/test.dart'; - -void main() { - group('State Reducer', () { - test('should add a todo to the list in response to an AddTodoAction', () { - final todo = Todo('Hallo'); - final store = Store( - reducerBuilder.build(), - AppState(), - AppActions(), - ); - - store.actions.addTodoAction(todo); - - expect(store.state.todos, [todo]); - }); - - test('should remove from the list in response to a DeleteTodoAction', () { - final todo = Todo('Hallo'); - final store = Store( - reducerBuilder.build(), - AppState.fromTodos([todo]), - AppActions(), - ); - - expect(store.state.todos, [todo]); - - store.actions.deleteTodoAction(todo.id); - - expect(store.state.todos, []); - }); - - test('should update a todo in response to an UpdateTodoAction', () { - final todo = Todo('Hallo'); - final updatedTodo = todo.rebuild((b) => b.task = 'Tschuss'); - final store = Store( - reducerBuilder.build(), - AppState.fromTodos([todo]), - AppActions(), - ); - - store.actions - .updateTodoAction(UpdateTodoActionPayload(todo.id, updatedTodo)); - - expect(store.state.todos, [updatedTodo]); - }); - - test('should clear completed todos', () { - final todo1 = Todo('Hallo'); - final todo2 = Todo.builder( - (b) => b - ..task = 'Tschüss' - ..complete = true, - ); - final store = Store( - reducerBuilder.build(), - AppState.fromTodos([todo1, todo2]), - AppActions(), - ); - - expect(store.state.todos, [todo1, todo2]); - - store.actions.clearCompletedAction(); - - expect(store.state.todos, [todo1]); - }); - - test('should mark all as completed if some todos are incomplete', () { - final todo1 = Todo('Hallo'); - final todo2 = Todo.builder( - (b) => b - ..task = 'Tschüss' - ..complete = true, - ); - final store = Store( - reducerBuilder.build(), - AppState.fromTodos([todo1, todo2]), - AppActions(), - ); - - expect(store.state.todos, [todo1, todo2]); - - store.actions.toggleAllAction(); - - expect(store.state.allCompleteSelector, isTrue); - }); - - test('should mark all as incomplete if all todos are complete', () { - final todo1 = Todo.builder( - (b) => b - ..task = 'Hallo' - ..complete = true, - ); - final todo2 = Todo.builder( - (b) => b - ..task = 'Tschüss' - ..complete = true, - ); - final store = Store( - reducerBuilder.build(), - AppState.fromTodos([todo1, todo2]), - AppActions(), - ); - - expect(store.state.todos, [todo1, todo2]); - - store.actions.toggleAllAction(); - - expect(store.state.allCompleteSelector, isFalse); - expect(store.state.todos.every((todo) => !todo.complete), isTrue); - }); - - test('should update the VisibilityFilter', () { - final store = Store( - reducerBuilder.build(), - AppState(), - AppActions(), - ); - - store.actions.updateFilterAction(VisibilityFilter.completed); - - expect(store.state.activeFilter, VisibilityFilter.completed); - }); - - test('should update the AppTab', () { - final store = Store( - reducerBuilder.build(), - AppState(), - AppActions(), - ); - - store.actions.updateTabAction(AppTab.stats); - - expect(store.state.activeTab, AppTab.stats); - }); - }); -} diff --git a/built_redux/test/todos_repository_test.dart b/built_redux/test/todos_repository_test.dart deleted file mode 100644 index 518dca45..00000000 --- a/built_redux/test/todos_repository_test.dart +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:built_redux_sample/data/file_storage.dart'; -import 'package:built_redux_sample/data/todos_repository.dart'; -import 'package:built_redux_sample/data/web_client.dart'; -import 'package:built_redux_sample/models/models.dart'; -import 'package:mockito/mockito.dart'; -import 'package:test/test.dart'; - -/// We create two Mocks for our Web Service and File Storage. We will use these -/// mock classes to verify the behavior of the TodosService. -class MockFileStorage extends Mock implements FileStorage {} - -class MockWebService extends Mock implements WebClient {} - -void main() { - group('TodosRepository', () { - test( - 'should load todos from File Storage if they exist without calling the web service', - () { - final fileStorage = MockFileStorage(); - final webService = MockWebService(); - final todosService = TodosRepository( - fileStorage: fileStorage, - webClient: webService, - ); - final todos = [Todo('Task')]; - - // We'll use our mock throughout the tests to set certain conditions. In - // this first test, we want to mock out our file storage to return a - // list of Todos that we define here in our test! - when(fileStorage.loadTodos()).thenAnswer((_) => Future.value(todos)); - - expect(todosService.loadTodos(), completion(todos)); - verifyNever(webService.fetchTodos()); - }); - - test( - 'should fetch todos from the Web Service if the file storage throws a synchronous error', - () async { - final fileStorage = MockFileStorage(); - final webService = MockWebService(); - final todosService = TodosRepository( - fileStorage: fileStorage, - webClient: webService, - ); - final todos = [Todo('Task')]; - - // In this instance, we'll ask our Mock to throw an error. When it does, - // we expect the web service to be called instead. - when(fileStorage.loadTodos()) - .thenAnswer((_) => Future>.error('Oh no')); - when(webService.fetchTodos()).thenAnswer((_) => Future.value(todos)); - - // We check that the correct todos were returned, and that the - // webService.fetchTodos method was in fact called! - expect(await todosService.loadTodos(), todos); - verify(webService.fetchTodos()); - }); - - test( - 'should fetch todos from the Web Service if the File storage returns an async error', - () async { - final fileStorage = MockFileStorage(); - final webService = MockWebService(); - final todosService = TodosRepository( - fileStorage: fileStorage, - webClient: webService, - ); - final todos = [Todo('Task')]; - - when(fileStorage.loadTodos()) - .thenAnswer((_) => Future>.error('Oh no')); - when(webService.fetchTodos()).thenAnswer((_) => Future.value(todos)); - - expect(await todosService.loadTodos(), todos); - verify(webService.fetchTodos()); - }); - - test('should persist the todos to local disk and the web service', () { - final fileStorage = MockFileStorage(); - final webService = MockWebService(); - final todosService = TodosRepository( - fileStorage: fileStorage, - webClient: webService, - ); - final todos = [Todo('Task')]; - - when(fileStorage.saveTodos(todos)).thenAnswer((_) async => null); - when(webService.postTodos(todos)).thenAnswer((_) async => true); - - // In this case, we just want to verify we're correctly persisting to all - // the storage mechanisms we care about. - expect(todosService.saveTodos(todos), completes); - verify(fileStorage.saveTodos(todos)); - verify(webService.postTodos(todos)); - }); - }); -} diff --git a/built_redux/test_driver/todo_app.dart b/built_redux/test_driver/todo_app.dart deleted file mode 100644 index 2a446786..00000000 --- a/built_redux/test_driver/todo_app.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// This line imports the extension -import 'package:built_redux_sample/main.dart' as app; -import 'package:flutter_driver/driver_extension.dart'; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/built_redux/test_driver/todo_app_test.dart b/built_redux/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/built_redux/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/change_notifier_provider/.metadata b/change_notifier_provider/.metadata index 361e1e4c..05a8ab44 100644 --- a/change_notifier_provider/.metadata +++ b/change_notifier_provider/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: 18cd7a3601bcffb36fdf2f679f763b5e827c2e8e - channel: beta + revision: "05db9689081f091050f01aed79f04dce0c750154" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: android + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: ios + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: linux + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: macos + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: web + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: windows + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/change_notifier_provider/analysis_options.yaml b/change_notifier_provider/analysis_options.yaml new file mode 100644 index 00000000..134f2137 --- /dev/null +++ b/change_notifier_provider/analysis_options.yaml @@ -0,0 +1,34 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# 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 +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + # The lint rules applied to this project can be customized in the + # 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 + # and their documentation is published at https://dart.dev/lints. + # + # 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 + # 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 + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/change_notifier_provider/android/.gitignore b/change_notifier_provider/android/.gitignore index bc2100d8..be3943c9 100644 --- a/change_notifier_provider/android/.gitignore +++ b/change_notifier_provider/android/.gitignore @@ -5,3 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/change_notifier_provider/android/app/build.gradle b/change_notifier_provider/android/app/build.gradle deleted file mode 100644 index 84853055..00000000 --- a/change_notifier_provider/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.change_notifier_provider" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/change_notifier_provider/android/app/build.gradle.kts b/change_notifier_provider/android/app/build.gradle.kts new file mode 100644 index 00000000..cbc4befb --- /dev/null +++ b/change_notifier_provider/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.change_notifier_provider_sample" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.change_notifier_provider_sample" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/change_notifier_provider/android/app/src/debug/AndroidManifest.xml b/change_notifier_provider/android/app/src/debug/AndroidManifest.xml index a9a5b33e..399f6981 100644 --- a/change_notifier_provider/android/app/src/debug/AndroidManifest.xml +++ b/change_notifier_provider/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/change_notifier_provider/android/app/src/main/AndroidManifest.xml b/change_notifier_provider/android/app/src/main/AndroidManifest.xml index afb0b62e..3e5f710b 100644 --- a/change_notifier_provider/android/app/src/main/AndroidManifest.xml +++ b/change_notifier_provider/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,25 @@ - - + + + @@ -27,4 +31,15 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + diff --git a/change_notifier_provider/android/app/src/main/kotlin/com/example/change_notifier_provider/MainActivity.kt b/change_notifier_provider/android/app/src/main/kotlin/com/example/change_notifier_provider/MainActivity.kt deleted file mode 100644 index 891c3153..00000000 --- a/change_notifier_provider/android/app/src/main/kotlin/com/example/change_notifier_provider/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.change_notifier_provider - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/change_notifier_provider/android/app/src/main/kotlin/com/example/change_notifier_provider_sample/MainActivity.kt b/change_notifier_provider/android/app/src/main/kotlin/com/example/change_notifier_provider_sample/MainActivity.kt new file mode 100644 index 00000000..304eb04b --- /dev/null +++ b/change_notifier_provider/android/app/src/main/kotlin/com/example/change_notifier_provider_sample/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.change_notifier_provider_sample + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/change_notifier_provider/android/app/src/main/res/drawable-v21/launch_background.xml b/change_notifier_provider/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/change_notifier_provider/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/change_notifier_provider/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/change_notifier_provider/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index a3f285f9..db77bb4b 100644 Binary files a/change_notifier_provider/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/change_notifier_provider/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/change_notifier_provider/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/change_notifier_provider/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 5e6f3ac6..17987b79 100644 Binary files a/change_notifier_provider/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/change_notifier_provider/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/change_notifier_provider/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/change_notifier_provider/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 144d60be..09d43914 100644 Binary files a/change_notifier_provider/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/change_notifier_provider/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/change_notifier_provider/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/change_notifier_provider/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index deafae2d..d5f1c8d3 100644 Binary files a/change_notifier_provider/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/change_notifier_provider/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/change_notifier_provider/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/change_notifier_provider/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index d5614ac8..4d6372ee 100644 Binary files a/change_notifier_provider/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/change_notifier_provider/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/change_notifier_provider/android/app/src/main/res/values-night/styles.xml b/change_notifier_provider/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/change_notifier_provider/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/change_notifier_provider/android/app/src/main/res/values/styles.xml b/change_notifier_provider/android/app/src/main/res/values/styles.xml index 00fa4417..cb1ef880 100644 --- a/change_notifier_provider/android/app/src/main/res/values/styles.xml +++ b/change_notifier_provider/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ - + + diff --git a/change_notifier_provider/android/app/src/profile/AndroidManifest.xml b/change_notifier_provider/android/app/src/profile/AndroidManifest.xml index a9a5b33e..399f6981 100644 --- a/change_notifier_provider/android/app/src/profile/AndroidManifest.xml +++ b/change_notifier_provider/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/change_notifier_provider/android/build.gradle b/change_notifier_provider/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/change_notifier_provider/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/change_notifier_provider/android/build.gradle.kts b/change_notifier_provider/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/change_notifier_provider/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/change_notifier_provider/android/gradle.properties b/change_notifier_provider/android/gradle.properties index 38c8d454..f018a618 100644 --- a/change_notifier_provider/android/gradle.properties +++ b/change_notifier_provider/android/gradle.properties @@ -1,4 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/change_notifier_provider/android/gradle/wrapper/gradle-wrapper.properties b/change_notifier_provider/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..ac3b4792 100644 --- a/change_notifier_provider/android/gradle/wrapper/gradle-wrapper.properties +++ b/change_notifier_provider/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/change_notifier_provider/android/settings.gradle b/change_notifier_provider/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/change_notifier_provider/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/change_notifier_provider/android/settings.gradle.kts b/change_notifier_provider/android/settings.gradle.kts new file mode 100644 index 00000000..fb605bc8 --- /dev/null +++ b/change_notifier_provider/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/change_notifier_provider/integration_test/app_test.dart b/change_notifier_provider/integration_test/app_test.dart new file mode 100644 index 00000000..7904d407 --- /dev/null +++ b/change_notifier_provider/integration_test/app_test.dart @@ -0,0 +1,19 @@ +import 'package:change_notifier_provider_sample/app.dart'; +import 'package:integration_tests/integration_tests.dart' as integration_tests; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; + +void main() { + integration_tests.run( + appBuilder: () async { + return ProviderApp( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'change_notifier_provider_test_${DateTime.now().toIso8601String()}', + await SharedPreferences.getInstance(), + ), + ), + ); + }, + ); +} diff --git a/change_notifier_provider/ios/.gitignore b/change_notifier_provider/ios/.gitignore index e96ef602..7a7f9873 100644 --- a/change_notifier_provider/ios/.gitignore +++ b/change_notifier_provider/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/change_notifier_provider/ios/Flutter/AppFrameworkInfo.plist b/change_notifier_provider/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f78..1dc6cf76 100644 --- a/change_notifier_provider/ios/Flutter/AppFrameworkInfo.plist +++ b/change_notifier_provider/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 13.0 diff --git a/change_notifier_provider/ios/Flutter/Debug.xcconfig b/change_notifier_provider/ios/Flutter/Debug.xcconfig index e8efba11..ec97fc6f 100644 --- a/change_notifier_provider/ios/Flutter/Debug.xcconfig +++ b/change_notifier_provider/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/change_notifier_provider/ios/Flutter/Release.xcconfig b/change_notifier_provider/ios/Flutter/Release.xcconfig index 399e9340..c4855bfe 100644 --- a/change_notifier_provider/ios/Flutter/Release.xcconfig +++ b/change_notifier_provider/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/change_notifier_provider/ios/Podfile b/change_notifier_provider/ios/Podfile index b30a428b..620e46eb 100644 --- a/change_notifier_provider/ios/Podfile +++ b/change_notifier_provider/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -10,81 +10,34 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - generated_key_values + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' +flutter_ios_podfile_setup - # Plugin Pods +target 'Runner' do + use_frameworks! - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths end end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/change_notifier_provider/ios/Runner.xcodeproj/project.pbxproj b/change_notifier_provider/ios/Runner.xcodeproj/project.pbxproj index a50c875c..26ec136d 100644 --- a/change_notifier_provider/ios/Runner.xcodeproj/project.pbxproj +++ b/change_notifier_provider/ios/Runner.xcodeproj/project.pbxproj @@ -3,22 +3,29 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -26,8 +33,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -37,14 +42,14 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -57,20 +62,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -84,6 +93,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -91,6 +101,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -102,7 +113,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -111,16 +121,26 @@ path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; @@ -147,9 +167,14 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -157,7 +182,7 @@ }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -170,11 +195,19 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -191,20 +224,23 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -220,6 +256,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -231,6 +275,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -253,9 +305,9 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -285,6 +337,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -293,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -309,18 +362,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProvider; + PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProviderSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -328,11 +377,58 @@ }; name = Profile; }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProviderSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProviderSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProviderSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -362,6 +458,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -376,7 +473,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -386,9 +483,9 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -418,6 +515,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -426,11 +524,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -443,18 +542,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProvider; + PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProviderSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -470,18 +565,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProvider; + PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProviderSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -492,6 +583,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/change_notifier_provider/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/change_notifier_provider/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/change_notifier_provider/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/change_notifier_provider/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/change_notifier_provider/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/change_notifier_provider/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/change_notifier_provider/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/change_notifier_provider/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/change_notifier_provider/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/change_notifier_provider/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/change_notifier_provider/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/change_notifier_provider/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..e3773d42 100644 --- a/change_notifier_provider/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/change_notifier_provider/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + + + + + @@ -61,8 +73,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - + + + + IDEDidComputeMac32BitWarning + + + diff --git a/change_notifier_provider/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/change_notifier_provider/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/change_notifier_provider/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/change_notifier_provider/ios/Runner/AppDelegate.swift b/change_notifier_provider/ios/Runner/AppDelegate.swift index 70693e4a..62666446 100644 --- a/change_notifier_provider/ios/Runner/AppDelegate.swift +++ b/change_notifier_provider/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ -import UIKit import Flutter +import UIKit -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d22f10b2..d36b1fab 100644 --- a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -107,6 +107,12 @@ "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" } ], "info" : { diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 980e5ad6..7353c41e 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index fd870289..797d452e 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 75e84cd1..6ed2d933 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 03ab8a84..4cd7b009 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index a03431cb..fe730945 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index f47613ee..321773cd 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 7f2230a9..797d452e 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 42315c6d..502f463a 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index f9882cc0..0ec30343 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 45537513..0ec30343 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 6360ea17..e9f5fea2 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 152d5e12..84ac32ae 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 310b0b8f..8953cba0 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 092b7bfe..0467bf12 100644 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/change_notifier_provider/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/change_notifier_provider/ios/Runner/Info.plist b/change_notifier_provider/ios/Runner/Info.plist index cbeedc31..2d54d440 100644 --- a/change_notifier_provider/ios/Runner/Info.plist +++ b/change_notifier_provider/ios/Runner/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Change Notifier Provider Sample CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -11,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - change_notifier_provider + change_notifier_provider_sample CFBundlePackageType APPL CFBundleShortVersionString @@ -39,7 +41,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/change_notifier_provider/ios/Runner/Runner-Bridging-Header.h b/change_notifier_provider/ios/Runner/Runner-Bridging-Header.h index 7335fdf9..308a2a56 100644 --- a/change_notifier_provider/ios/Runner/Runner-Bridging-Header.h +++ b/change_notifier_provider/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file +#import "GeneratedPluginRegistrant.h" diff --git a/change_notifier_provider/ios/RunnerTests/RunnerTests.swift b/change_notifier_provider/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/change_notifier_provider/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/change_notifier_provider/lib/add_todo_screen.dart b/change_notifier_provider/lib/add_todo_screen.dart index d12e1b0f..75a94926 100644 --- a/change_notifier_provider/lib/add_todo_screen.dart +++ b/change_notifier_provider/lib/add_todo_screen.dart @@ -9,10 +9,10 @@ class AddTodoScreen extends StatefulWidget { const AddTodoScreen() : super(key: ArchSampleKeys.addTodoScreen); @override - _AddTodoScreenState createState() => _AddTodoScreenState(); + AddTodoScreenState createState() => AddTodoScreenState(); } -class _AddTodoScreenState extends State { +class AddTodoScreenState extends State { final _formKey = GlobalKey(); final _titleEditingController = TextEditingController(); final _notesEditingController = TextEditingController(); @@ -30,12 +30,10 @@ class _AddTodoScreenState extends State { final textTheme = Theme.of(context).textTheme; return Scaffold( - appBar: AppBar( - title: Text(localizations.addTodo), - ), + appBar: AppBar(title: Text(localizations.addTodo)), body: Form( key: _formKey, - autovalidate: false, + autovalidateMode: AutovalidateMode.always, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -46,10 +44,10 @@ class _AddTodoScreenState extends State { decoration: InputDecoration( hintText: localizations.newTodoHint, ), - style: textTheme.headline, + style: textTheme.titleLarge, autofocus: true, validator: (val) { - return val.trim().isEmpty + return val != null && val.trim().isEmpty ? localizations.emptyTodoError : null; }, @@ -57,10 +55,10 @@ class _AddTodoScreenState extends State { TextFormField( key: ArchSampleKeys.noteField, controller: _notesEditingController, - style: textTheme.subhead, + style: textTheme.titleMedium, decoration: InputDecoration(hintText: localizations.notesHint), maxLines: 10, - ) + ), ], ), ), @@ -69,11 +67,13 @@ class _AddTodoScreenState extends State { key: ArchSampleKeys.saveNewTodo, tooltip: localizations.addTodo, onPressed: () { - if (_formKey.currentState.validate()) { - Provider.of(context, listen: false).addTodo(Todo( - _titleEditingController.text, - note: _notesEditingController.text, - )); + if (_formKey.currentState!.validate()) { + Provider.of(context, listen: false).addTodo( + Todo( + _titleEditingController.text, + note: _notesEditingController.text, + ), + ); Navigator.pop(context); } }, diff --git a/change_notifier_provider/lib/app.dart b/change_notifier_provider/lib/app.dart index 3bfe8b61..21842c37 100644 --- a/change_notifier_provider/lib/app.dart +++ b/change_notifier_provider/lib/app.dart @@ -1,13 +1,8 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:meta/meta.dart'; -import 'package:provider/provider.dart'; import 'package:change_notifier_provider_sample/add_todo_screen.dart'; import 'package:change_notifier_provider_sample/localization.dart'; import 'package:change_notifier_provider_sample/todo_list_model.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -16,16 +11,15 @@ import 'home/home_screen.dart'; class ProviderApp extends StatelessWidget { final TodosRepository repository; - ProviderApp({ - @required this.repository, - }); + const ProviderApp({super.key, required this.repository}); @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (_) => TodoListModel(repository: repository)..loadTodos(), child: MaterialApp( - theme: ArchSampleTheme.theme, + theme: ArchSampleTheme.lightTheme, + darkTheme: ArchSampleTheme.darkTheme, localizationsDelegates: [ ArchSampleLocalizationsDelegate(), ProviderLocalizationsDelegate(), diff --git a/change_notifier_provider/lib/details_screen.dart b/change_notifier_provider/lib/details_screen.dart index d6e96a36..408ab86d 100644 --- a/change_notifier_provider/lib/details_screen.dart +++ b/change_notifier_provider/lib/details_screen.dart @@ -1,18 +1,17 @@ +import 'package:change_notifier_provider_sample/todo_list_model.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:change_notifier_provider_sample/todo_list_model.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'edit_todo_screen.dart'; import 'models.dart'; -import 'todo_list_model.dart'; class DetailsScreen extends StatelessWidget { final String id; final VoidCallback onRemove; - const DetailsScreen({@required this.id, @required this.onRemove}) - : super(key: ArchSampleKeys.todoDetailsScreen); + const DetailsScreen({required this.id, required this.onRemove}) + : super(key: ArchSampleKeys.todoDetailsScreen); @override Widget build(BuildContext context) { @@ -25,10 +24,10 @@ class DetailsScreen extends StatelessWidget { tooltip: ArchSampleLocalizations.of(context).deleteTodo, icon: const Icon(Icons.delete), onPressed: onRemove, - ) + ), ], ), - body: Selector( + body: Selector( selector: (context, model) => model.todoById(id), shouldRebuild: (prev, next) => next != null, builder: (context, todo, _) { @@ -43,10 +42,12 @@ class DetailsScreen extends StatelessWidget { padding: const EdgeInsets.only(right: 8.0), child: Checkbox( key: ArchSampleKeys.detailsTodoItemCheckbox, - value: todo.complete, + value: todo?.complete, onChanged: (complete) { - Provider.of(context, listen: false) - .updateTodo(todo.copy(complete: !todo.complete)); + Provider.of( + context, + listen: false, + ).updateTodo(todo!.copy(complete: !todo.complete)); }, ), ), @@ -60,16 +61,16 @@ class DetailsScreen extends StatelessWidget { bottom: 16.0, ), child: Text( - todo.task, + todo!.task, key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, ), ), Text( todo.note, key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) + style: Theme.of(context).textTheme.titleMedium, + ), ], ), ), @@ -85,15 +86,17 @@ class DetailsScreen extends StatelessWidget { onPressed: () { Navigator.push( context, - MaterialPageRoute( + MaterialPageRoute( builder: (context) => EditTodoScreen( id: id, onEdit: (task, note) { - final model = - Provider.of(context, listen: false); + final model = Provider.of( + context, + listen: false, + ); final todo = model.todoById(id); - model.updateTodo(todo.copy(task: task, note: note)); + model.updateTodo(todo!.copy(task: task, note: note)); return Navigator.pop(context); }, diff --git a/change_notifier_provider/lib/edit_todo_screen.dart b/change_notifier_provider/lib/edit_todo_screen.dart index b50ef9dc..fb8fcd42 100644 --- a/change_notifier_provider/lib/edit_todo_screen.dart +++ b/change_notifier_provider/lib/edit_todo_screen.dart @@ -1,30 +1,30 @@ +import 'package:change_notifier_provider_sample/todo_list_model.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:change_notifier_provider_sample/todo_list_model.dart'; import 'package:todos_app_core/todos_app_core.dart'; class EditTodoScreen extends StatefulWidget { final void Function(String task, String note) onEdit; final String id; - const EditTodoScreen({ - @required this.id, - @required this.onEdit, - }) : super(key: ArchSampleKeys.editTodoScreen); + const EditTodoScreen({required this.id, required this.onEdit}) + : super(key: ArchSampleKeys.editTodoScreen); @override - _EditTodoScreenState createState() => _EditTodoScreenState(); + EditTodoScreenState createState() => EditTodoScreenState(); } -class _EditTodoScreenState extends State { +class EditTodoScreenState extends State { final _formKey = GlobalKey(); - TextEditingController _taskController; - TextEditingController _noteController; + late final TextEditingController _taskController; + late final TextEditingController _noteController; @override void initState() { - final todo = - Provider.of(context, listen: false).todoById(widget.id); + final todo = Provider.of( + context, + listen: false, + ).todoById(widget.id); _taskController = TextEditingController(text: todo?.task); _noteController = TextEditingController(text: todo?.note); super.initState(); @@ -50,12 +50,12 @@ class _EditTodoScreenState extends State { TextFormField( controller: _taskController, key: ArchSampleKeys.taskField, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, decoration: InputDecoration( hintText: ArchSampleLocalizations.of(context).newTodoHint, ), validator: (val) { - return val.trim().isEmpty + return val != null && val.trim().isEmpty ? ArchSampleLocalizations.of(context).emptyTodoError : null; }, @@ -67,7 +67,7 @@ class _EditTodoScreenState extends State { hintText: ArchSampleLocalizations.of(context).notesHint, ), maxLines: 10, - ) + ), ], ), ), @@ -76,8 +76,8 @@ class _EditTodoScreenState extends State { key: ArchSampleKeys.saveTodoFab, tooltip: ArchSampleLocalizations.of(context).saveChanges, onPressed: () { - if (_formKey.currentState.validate()) { - _formKey.currentState.save(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); widget.onEdit(_taskController.text, _noteController.text); } }, diff --git a/change_notifier_provider/lib/home/extra_actions_button.dart b/change_notifier_provider/lib/home/extra_actions_button.dart index 81ac1b9f..7bcd31c0 100644 --- a/change_notifier_provider/lib/home/extra_actions_button.dart +++ b/change_notifier_provider/lib/home/extra_actions_button.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; @@ -9,9 +5,7 @@ import 'package:todos_app_core/todos_app_core.dart'; import '../todo_list_model.dart'; class ExtraActionsButton extends StatelessWidget { - const ExtraActionsButton({ - Key key, - }) : super(key: key); + const ExtraActionsButton({super.key}); @override Widget build(BuildContext context) { @@ -34,9 +28,11 @@ class ExtraActionsButton extends StatelessWidget { PopupMenuItem( key: ArchSampleKeys.toggleAll, value: ExtraAction.toggleAllComplete, - child: Text(model.hasActiveTodos - ? ArchSampleLocalizations.of(context).markAllComplete - : ArchSampleLocalizations.of(context).markAllIncomplete), + child: Text( + model.hasActiveTodos + ? ArchSampleLocalizations.of(context).markAllComplete + : ArchSampleLocalizations.of(context).markAllIncomplete, + ), ), PopupMenuItem( key: ArchSampleKeys.clearCompleted, diff --git a/change_notifier_provider/lib/home/filter_button.dart b/change_notifier_provider/lib/home/filter_button.dart index 229c13dd..8f6ab785 100644 --- a/change_notifier_provider/lib/home/filter_button.dart +++ b/change_notifier_provider/lib/home/filter_button.dart @@ -1,16 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:change_notifier_provider_sample/todo_list_model.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:change_notifier_provider_sample/todo_list_model.dart'; import 'package:todos_app_core/todos_app_core.dart'; class FilterButton extends StatelessWidget { - final bool isActive; + const FilterButton({super.key, required this.isActive}); - const FilterButton({this.isActive, Key key}) : super(key: key); + final bool isActive; @override Widget build(BuildContext context) { @@ -36,12 +32,13 @@ class FilterButton extends StatelessWidget { } List> _items( - BuildContext context, TodoListModel store) { - final activeStyle = Theme.of(context) - .textTheme - .body1 - .copyWith(color: Theme.of(context).accentColor); - final defaultStyle = Theme.of(context).textTheme.body1; + BuildContext context, + TodoListModel store, + ) { + final activeStyle = Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).colorScheme.secondary, + ); + final defaultStyle = Theme.of(context).textTheme.bodyMedium; return [ PopupMenuItem( @@ -49,8 +46,9 @@ class FilterButton extends StatelessWidget { value: VisibilityFilter.all, child: Text( ArchSampleLocalizations.of(context).showAll, - style: - store.filter == VisibilityFilter.all ? activeStyle : defaultStyle, + style: store.filter == VisibilityFilter.all + ? activeStyle + : defaultStyle, ), ), PopupMenuItem( diff --git a/change_notifier_provider/lib/home/home_screen.dart b/change_notifier_provider/lib/home/home_screen.dart index af67034e..5ea5641e 100644 --- a/change_notifier_provider/lib/home/home_screen.dart +++ b/change_notifier_provider/lib/home/home_screen.dart @@ -1,9 +1,9 @@ -import 'package:flutter/material.dart' hide Action; -import 'package:provider/provider.dart'; import 'package:change_notifier_provider_sample/home/stats_view.dart'; import 'package:change_notifier_provider_sample/home/todo_list_view.dart'; import 'package:change_notifier_provider_sample/localization.dart'; import 'package:change_notifier_provider_sample/todo_list_model.dart'; +import 'package:flutter/material.dart' hide Action; +import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; import '../models.dart'; @@ -11,13 +11,13 @@ import 'extra_actions_button.dart'; import 'filter_button.dart'; class HomeScreen extends StatefulWidget { - const HomeScreen(); + const HomeScreen({super.key}); @override - _HomeScreenState createState() => _HomeScreenState(); + HomeScreenState createState() => HomeScreenState(); } -class _HomeScreenState extends State { +class HomeScreenState extends State { // Because the state of the tabs is only a concern to the HomeScreen Widget, // it is stored as local state rather than in the TodoListModel. final _tab = ValueNotifier(_HomeScreenTab.todos); @@ -36,9 +36,8 @@ class _HomeScreenState extends State { actions: [ ValueListenableBuilder<_HomeScreenTab>( valueListenable: _tab, - builder: (_, tab, __) => FilterButton( - isActive: tab == _HomeScreenTab.todos, - ), + builder: (_, tab, _) => + FilterButton(isActive: tab == _HomeScreenTab.todos), ), const ExtraActionsButton(), ], @@ -67,11 +66,12 @@ class _HomeScreenState extends State { case _HomeScreenTab.stats: return const StatsView(); case _HomeScreenTab.todos: - default: return TodoListView( onRemove: (context, todo) { - Provider.of(context, listen: false) - .removeTodo(todo); + Provider.of( + context, + listen: false, + ).removeTodo(todo); _showUndoSnackbar(context, todo); }, ); @@ -90,11 +90,11 @@ class _HomeScreenState extends State { items: [ BottomNavigationBarItem( icon: Icon(Icons.list, key: ArchSampleKeys.todoTab), - title: Text(ArchSampleLocalizations.of(context).todos), + label: ArchSampleLocalizations.of(context).todos, ), BottomNavigationBarItem( icon: Icon(Icons.show_chart, key: ArchSampleKeys.statsTab), - title: Text(ArchSampleLocalizations.of(context).stats), + label: ArchSampleLocalizations.of(context).stats, ), ], ); @@ -104,7 +104,7 @@ class _HomeScreenState extends State { } void _showUndoSnackbar(BuildContext context, Todo todo) { - Scaffold.of(context).showSnackBar( + ScaffoldMessenger.of(context).showSnackBar( SnackBar( key: ArchSampleKeys.snackbar, duration: const Duration(seconds: 2), diff --git a/change_notifier_provider/lib/home/stats_view.dart b/change_notifier_provider/lib/home/stats_view.dart index f6566284..20945f32 100644 --- a/change_notifier_provider/lib/home/stats_view.dart +++ b/change_notifier_provider/lib/home/stats_view.dart @@ -1,11 +1,10 @@ -import 'package:flutter/cupertino.dart'; +import 'package:change_notifier_provider_sample/todo_list_model.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:change_notifier_provider_sample/todo_list_model.dart'; import 'package:todos_app_core/todos_app_core.dart'; class StatsView extends StatelessWidget { - const StatsView(); + const StatsView({super.key}); @override Widget build(BuildContext context) { @@ -17,7 +16,7 @@ class StatsView extends StatelessWidget { padding: const EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -27,7 +26,7 @@ class StatsView extends StatelessWidget { builder: (context, numCompleted, _) => Text( '$numCompleted', key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ), @@ -35,7 +34,7 @@ class StatsView extends StatelessWidget { padding: const EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -45,10 +44,10 @@ class StatsView extends StatelessWidget { builder: (context, numActive, _) => Text( '$numActive', key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), - ) + ), ], ), ); diff --git a/change_notifier_provider/lib/home/todo_list_view.dart b/change_notifier_provider/lib/home/todo_list_view.dart index ef34d820..ad3d19c1 100644 --- a/change_notifier_provider/lib/home/todo_list_view.dart +++ b/change_notifier_provider/lib/home/todo_list_view.dart @@ -1,6 +1,6 @@ +import 'package:change_notifier_provider_sample/todo_list_model.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:change_notifier_provider_sample/todo_list_model.dart'; import 'package:todos_app_core/todos_app_core.dart'; import '../details_screen.dart'; @@ -9,7 +9,7 @@ import '../models.dart'; class TodoListView extends StatelessWidget { final void Function(BuildContext context, Todo todo) onRemove; - TodoListView({Key key, @required this.onRemove}) : super(key: key); + const TodoListView({super.key, required this.onRemove}); @override Widget build(BuildContext context) { @@ -29,10 +29,10 @@ class TodoListView extends StatelessWidget { onTap: () { Navigator.push( context, - MaterialPageRoute( + MaterialPageRoute( builder: (_) { return DetailsScreen( - id: todo?.id, + id: todo.id, onRemove: () { Navigator.pop(context); onRemove(context, todo); @@ -46,21 +46,23 @@ class TodoListView extends StatelessWidget { key: ArchSampleKeys.todoItemCheckbox(todo.id), value: todo.complete, onChanged: (complete) { - Provider.of(context, listen: false) - .updateTodo(todo.copy(complete: complete)); + Provider.of( + context, + listen: false, + ).updateTodo(todo.copy(complete: complete)); }, ), title: Text( todo.task, key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), subtitle: Text( todo.note, key: ArchSampleKeys.todoItemNote(todo.id), maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ); diff --git a/change_notifier_provider/lib/localization.dart b/change_notifier_provider/lib/localization.dart index 9ca0b67d..f18a6a0c 100644 --- a/change_notifier_provider/lib/localization.dart +++ b/change_notifier_provider/lib/localization.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; @@ -9,7 +5,9 @@ import 'package:flutter/material.dart'; class ProviderLocalizations { static ProviderLocalizations of(BuildContext context) { return Localizations.of( - context, ProviderLocalizations); + context, + ProviderLocalizations, + )!; } String get appTitle => 'Provider Example'; diff --git a/change_notifier_provider/lib/main.dart b/change_notifier_provider/lib/main.dart index 4140e7de..a3e910fb 100644 --- a/change_notifier_provider/lib/main.dart +++ b/change_notifier_provider/lib/main.dart @@ -1,22 +1,19 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:change_notifier_provider_sample/app.dart'; import 'package:flutter/material.dart'; -import 'package:key_value_store_flutter/key_value_store_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(ProviderApp( - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'change_notifier_provider_todos', - FlutterKeyValueStore(await SharedPreferences.getInstance()), + runApp( + ProviderApp( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'change_notifier_provider_todos', + await SharedPreferences.getInstance(), + ), ), ), - )); + ); } diff --git a/change_notifier_provider/lib/main_web.dart b/change_notifier_provider/lib/main_web.dart deleted file mode 100644 index 4adbf574..00000000 --- a/change_notifier_provider/lib/main_web.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:html'; - -import 'package:change_notifier_provider_sample/app.dart'; -import 'package:flutter/material.dart'; -import 'package:key_value_store_web/key_value_store_web.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(ProviderApp( - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'change_notifier_provider', - WebKeyValueStore(window.localStorage), - ), - ), - )); -} diff --git a/change_notifier_provider/lib/models.dart b/change_notifier_provider/lib/models.dart index 699321cb..8568ae9d 100644 --- a/change_notifier_provider/lib/models.dart +++ b/change_notifier_provider/lib/models.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -15,12 +11,11 @@ class Todo { final String note; final String task; - Todo(this.task, {this.complete = false, this.note = '', String id}) - : id = id ?? Uuid().generateV4(); + Todo(this.task, {this.complete = false, this.note = '', String? id}) + : id = id ?? Uuid().generateV4(); @override - int get hashCode => - complete.hashCode ^ task.hashCode ^ note.hashCode ^ id.hashCode; + int get hashCode => Object.hash(complete, task, note, id); @override bool operator ==(Object other) => @@ -44,13 +39,13 @@ class Todo { static Todo fromEntity(TodoEntity entity) { return Todo( entity.task, - complete: entity.complete ?? false, + complete: entity.complete, note: entity.note, id: entity.id, ); } - Todo copy({String task, bool complete, String note, String id}) { + Todo copy({String? task, bool? complete, String? note, String? id}) { return Todo( task ?? this.task, complete: complete ?? this.complete, diff --git a/change_notifier_provider/lib/todo_list_model.dart b/change_notifier_provider/lib/todo_list_model.dart index 4a725ee8..2c1cdb1c 100644 --- a/change_notifier_provider/lib/todo_list_model.dart +++ b/change_notifier_provider/lib/todo_list_model.dart @@ -1,13 +1,8 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; -import 'dart:collection'; -import 'package:flutter/widgets.dart'; -import 'package:meta/meta.dart'; import 'package:change_notifier_provider_sample/models.dart'; +import 'package:collection/collection.dart'; +import 'package:flutter/widgets.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; enum VisibilityFilter { all, active, completed } @@ -33,27 +28,30 @@ class TodoListModel extends ChangeNotifier { bool get isLoading => _isLoading; TodoListModel({ - @required this.repository, - VisibilityFilter filter, - List todos, - }) : _todos = todos ?? [], - _filter = filter ?? VisibilityFilter.all; + required this.repository, + VisibilityFilter? filter, + List? todos, + }) : _todos = todos ?? [], + _filter = filter ?? VisibilityFilter.all; /// Loads remote data /// /// Call this initially and when the user manually refreshes - Future loadTodos() { + Future loadTodos() { _isLoading = true; notifyListeners(); - return repository.loadTodos().then((loadedTodos) { - _todos.addAll(loadedTodos.map(Todo.fromEntity)); - _isLoading = false; - notifyListeners(); - }).catchError((err) { - _isLoading = false; - notifyListeners(); - }); + return repository + .loadTodos() + .then((loadedTodos) { + _todos.addAll(loadedTodos.map(Todo.fromEntity)); + _isLoading = false; + notifyListeners(); + }) + .catchError((err) { + _isLoading = false; + notifyListeners(); + }); } List get filteredTodos { @@ -64,7 +62,6 @@ class TodoListModel extends ChangeNotifier { case VisibilityFilter.completed: return todo.complete; case VisibilityFilter.all: - default: return true; } }).toList(); @@ -85,8 +82,6 @@ class TodoListModel extends ChangeNotifier { /// updates a [Todo] by replacing the item with the same id by the parameter [todo] void updateTodo(Todo todo) { - assert(todo != null); - assert(todo.id != null); var oldTodo = _todos.firstWhere((it) => it.id == todo.id); var replaceIndex = _todos.indexOf(oldTodo); _todos.replaceRange(replaceIndex, replaceIndex + 1, [todo]); @@ -110,9 +105,7 @@ class TodoListModel extends ChangeNotifier { repository.saveTodos(_todos.map((it) => it.toEntity()).toList()); } - Todo todoById(String id) { - return _todos.firstWhere((it) => it.id == id, orElse: () => null); - } + Todo? todoById(String id) => _todos.firstWhereOrNull((it) => it.id == id); int get numCompleted => todos.where((Todo todo) => todo.complete).toList().length; diff --git a/change_notifier_provider/linux/.gitignore b/change_notifier_provider/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/change_notifier_provider/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/change_notifier_provider/linux/CMakeLists.txt b/change_notifier_provider/linux/CMakeLists.txt new file mode 100644 index 00000000..64aa7f7c --- /dev/null +++ b/change_notifier_provider/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +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 "change_notifier_provider_sample") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.change_notifier_provider_sample") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +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() + +# 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() + +# 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_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# 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 +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# 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() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +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) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/change_notifier_provider/linux/flutter/CMakeLists.txt b/change_notifier_provider/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/change_notifier_provider/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +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. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# 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/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter 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. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/change_notifier_provider/linux/flutter/generated_plugin_registrant.cc b/change_notifier_provider/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e71a16d2 --- /dev/null +++ b/change_notifier_provider/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/change_notifier_provider/linux/flutter/generated_plugin_registrant.h b/change_notifier_provider/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/change_notifier_provider/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/change_notifier_provider/linux/flutter/generated_plugins.cmake b/change_notifier_provider/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/change_notifier_provider/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + 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}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/change_notifier_provider/linux/runner/CMakeLists.txt b/change_notifier_provider/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/change_notifier_provider/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "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 +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/change_notifier_provider/linux/runner/main.cc b/change_notifier_provider/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/change_notifier_provider/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/change_notifier_provider/linux/runner/my_application.cc b/change_notifier_provider/linux/runner/my_application.cc new file mode 100644 index 00000000..5f0dfd38 --- /dev/null +++ b/change_notifier_provider/linux/runner/my_application.cc @@ -0,0 +1,144 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView *view) +{ + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // 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 + // desktop). + // 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. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "change_notifier_provider_sample"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "change_notifier_provider_sample"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/change_notifier_provider/linux/runner/my_application.h b/change_notifier_provider/linux/runner/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/change_notifier_provider/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/change_notifier_provider/macos/.gitignore b/change_notifier_provider/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/change_notifier_provider/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/change_notifier_provider/macos/Flutter/Flutter-Debug.xcconfig b/change_notifier_provider/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/change_notifier_provider/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/change_notifier_provider/macos/Flutter/Flutter-Release.xcconfig b/change_notifier_provider/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/change_notifier_provider/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/change_notifier_provider/macos/Flutter/GeneratedPluginRegistrant.swift b/change_notifier_provider/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b8e2b22f --- /dev/null +++ b/change_notifier_provider/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/change_notifier_provider/macos/Podfile b/change_notifier_provider/macos/Podfile new file mode 100644 index 00000000..ff5ddb3b --- /dev/null +++ b/change_notifier_provider/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/change_notifier_provider/macos/Podfile.lock b/change_notifier_provider/macos/Podfile.lock new file mode 100644 index 00000000..d2f9a639 --- /dev/null +++ b/change_notifier_provider/macos/Podfile.lock @@ -0,0 +1,30 @@ +PODS: + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + +SPEC CHECKSUMS: + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.16.2 diff --git a/change_notifier_provider/macos/Runner.xcodeproj/project.pbxproj b/change_notifier_provider/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..9bb5dd80 --- /dev/null +++ b/change_notifier_provider/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 0B6FA1F21900BA1572C89537 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B13AEC87397DCBA1150810C1 /* Pods_RunnerTests.framework */; }; + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 6ECBB7A679D57D47CD2F0938 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD0C88E040B6CE664C52F3E0 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0272F4665CC808F2D48CD5A0 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* change_notifier_provider_sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = change_notifier_provider_sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 74A48B0CF81074C297B54A4C /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 8AD233DA251D2331353A5927 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + AD0C88E040B6CE664C52F3E0 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B13AEC87397DCBA1150810C1 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BB1E40EA436A5E00602DC792 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + D222D73BEAEDF58B5FEE79C7 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + E32D156122B62226C4EBACFF /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0B6FA1F21900BA1572C89537 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 6ECBB7A679D57D47CD2F0938 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 6687F8B03C2B0B421B1955C1 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* change_notifier_provider_sample.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 6687F8B03C2B0B421B1955C1 /* Pods */ = { + isa = PBXGroup; + children = ( + 0272F4665CC808F2D48CD5A0 /* Pods-Runner.debug.xcconfig */, + D222D73BEAEDF58B5FEE79C7 /* Pods-Runner.release.xcconfig */, + E32D156122B62226C4EBACFF /* Pods-Runner.profile.xcconfig */, + 8AD233DA251D2331353A5927 /* Pods-RunnerTests.debug.xcconfig */, + BB1E40EA436A5E00602DC792 /* Pods-RunnerTests.release.xcconfig */, + 74A48B0CF81074C297B54A4C /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + AD0C88E040B6CE664C52F3E0 /* Pods_Runner.framework */, + B13AEC87397DCBA1150810C1 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 881E65D4C13D231022878D2B /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + F0DC327578E580FF97DA2A9E /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + E565D68D56F3B6717D3BC530 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* change_notifier_provider_sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 881E65D4C13D231022878D2B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + E565D68D56F3B6717D3BC530 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + F0DC327578E580FF97DA2A9E /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8AD233DA251D2331353A5927 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProviderSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/change_notifier_provider_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/change_notifier_provider_sample"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BB1E40EA436A5E00602DC792 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProviderSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/change_notifier_provider_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/change_notifier_provider_sample"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 74A48B0CF81074C297B54A4C /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProviderSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/change_notifier_provider_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/change_notifier_provider_sample"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/change_notifier_provider/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/change_notifier_provider/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/change_notifier_provider/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/change_notifier_provider/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/change_notifier_provider/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..aa9f0213 --- /dev/null +++ b/change_notifier_provider/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/change_notifier_provider/macos/Runner.xcworkspace/contents.xcworkspacedata b/change_notifier_provider/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/change_notifier_provider/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/change_notifier_provider/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/change_notifier_provider/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/change_notifier_provider/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/change_notifier_provider/macos/Runner/AppDelegate.swift b/change_notifier_provider/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/change_notifier_provider/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/change_notifier_provider/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/change_notifier_provider/macos/Runner/Base.lproj/MainMenu.xib b/change_notifier_provider/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/change_notifier_provider/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/change_notifier_provider/macos/Runner/Configs/AppInfo.xcconfig b/change_notifier_provider/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..0c7fa86c --- /dev/null +++ b/change_notifier_provider/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// 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 +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = change_notifier_provider_sample + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.changeNotifierProviderSample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/change_notifier_provider/macos/Runner/Configs/Debug.xcconfig b/change_notifier_provider/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/change_notifier_provider/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/change_notifier_provider/macos/Runner/Configs/Release.xcconfig b/change_notifier_provider/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/change_notifier_provider/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/change_notifier_provider/macos/Runner/Configs/Warnings.xcconfig b/change_notifier_provider/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/change_notifier_provider/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/change_notifier_provider/macos/Runner/DebugProfile.entitlements b/change_notifier_provider/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/change_notifier_provider/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/change_notifier_provider/macos/Runner/Info.plist b/change_notifier_provider/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/change_notifier_provider/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/change_notifier_provider/macos/Runner/MainFlutterWindow.swift b/change_notifier_provider/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/change_notifier_provider/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/change_notifier_provider/macos/Runner/Release.entitlements b/change_notifier_provider/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/change_notifier_provider/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/change_notifier_provider/macos/RunnerTests/RunnerTests.swift b/change_notifier_provider/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/change_notifier_provider/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/change_notifier_provider/pubspec.yaml b/change_notifier_provider/pubspec.yaml index f5c2a871..bc36b18c 100644 --- a/change_notifier_provider/pubspec.yaml +++ b/change_notifier_provider/pubspec.yaml @@ -12,29 +12,32 @@ description: A new Flutter project. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html version: 1.0.0+1 +publish_to: "none" environment: - sdk: ">=2.6.0 <3.0.0" + sdk: ^3.8.1 dependencies: - provider: ^4.0.4 - todos_repository_local_storage: - path: ../todos_repository_local_storage - todos_app_core: - path: ../todos_app_core + provider: + collection: flutter: sdk: flutter - key_value_store_flutter: - key_value_store_web: + todos_app_core: + path: ../todos_app_core + todos_repository_core: + path: ../todos_repository_core + todos_repository_local_storage: + path: ../todos_repository_local_storage shared_preferences: dev_dependencies: - mockito: - test: + flutter_lints: flutter_test: sdk: flutter - flutter_driver: + integration_test: sdk: flutter + test: + mockito: integration_tests: path: ../integration_tests diff --git a/change_notifier_provider/test/home_screen_test.dart b/change_notifier_provider/test/home_screen_test.dart index e2e17a64..29f05026 100644 --- a/change_notifier_provider/test/home_screen_test.dart +++ b/change_notifier_provider/test/home_screen_test.dart @@ -2,12 +2,10 @@ import 'package:change_notifier_provider_sample/home/home_screen.dart'; import 'package:change_notifier_provider_sample/localization.dart'; import 'package:change_notifier_provider_sample/models.dart'; import 'package:change_notifier_provider_sample/todo_list_model.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; import 'mock_repository.dart'; @@ -83,22 +81,13 @@ void main() { } class _TestWidget extends StatelessWidget { - final Widget child; - final TodosRepository repository; - final List todos; - - const _TestWidget({ - Key key, - this.child, - this.repository, - this.todos, - }) : super(key: key); + const _TestWidget(); @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (_) { - final repo = MockRepository(todos ?? _defaultTodos); + final repo = MockRepository(_defaultTodos); return TodoListModel(repository: repo)..loadTodos(); }, child: MaterialApp( @@ -106,7 +95,7 @@ class _TestWidget extends StatelessWidget { ProviderLocalizationsDelegate(), ArchSampleLocalizationsDelegate(), ], - home: child ?? const HomeScreen(), + home: const HomeScreen(), ), ); } @@ -123,10 +112,11 @@ class _TestWidget extends StatelessWidget { Matcher isChecked(bool isChecked) { return matchesSemantics( isChecked: isChecked, + hasTapAction: true, + hasFocusAction: true, hasCheckedState: true, + isFocusable: true, hasEnabledState: true, isEnabled: true, - isFocusable: true, - hasTapAction: true, ); } diff --git a/change_notifier_provider/test/mock_repository.dart b/change_notifier_provider/test/mock_repository.dart index bbe13c77..3069d88a 100644 --- a/change_notifier_provider/test/mock_repository.dart +++ b/change_notifier_provider/test/mock_repository.dart @@ -8,13 +8,13 @@ class MockRepository extends TodosRepository { int saveCount = 0; MockRepository([List todos = const []]) - : entities = todos.map((it) => it.toEntity()).toList(); + : entities = todos.map((it) => it.toEntity()).toList(); @override Future> loadTodos() async => entities; @override - Future saveTodos(List todos) async { + Future saveTodos(List todos) async { saveCount++; entities = todos; } diff --git a/change_notifier_provider/test/todo_list_model_test.dart b/change_notifier_provider/test/todo_list_model_test.dart index 9162ee02..79a68728 100644 --- a/change_notifier_provider/test/todo_list_model_test.dart +++ b/change_notifier_provider/test/todo_list_model_test.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:change_notifier_provider_sample/models.dart'; import 'package:change_notifier_provider_sample/todo_list_model.dart'; import 'package:test/test.dart'; @@ -41,33 +37,37 @@ void main() { expect(model.filteredTodos, todos); }); - test('should return active todos if the VisibilityFilter is active', - () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final model = TodoListModel( - filter: VisibilityFilter.active, - repository: MockRepository(), - todos: [todo1, todo2, todo3], - ); - - expect(model.filteredTodos, [todo1, todo2]); - }); - - test('should return completed todos if the VisibilityFilter is completed', - () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final model = TodoListModel( - filter: VisibilityFilter.completed, - repository: MockRepository(), - todos: [todo1, todo2, todo3], - ); - - expect(model.filteredTodos, [todo3]); - }); + test( + 'should return active todos if the VisibilityFilter is active', + () async { + final todo1 = Todo('a'); + final todo2 = Todo('b'); + final todo3 = Todo('c', complete: true); + final model = TodoListModel( + filter: VisibilityFilter.active, + repository: MockRepository(), + todos: [todo1, todo2, todo3], + ); + + expect(model.filteredTodos, [todo1, todo2]); + }, + ); + + test( + 'should return completed todos if the VisibilityFilter is completed', + () async { + final todo1 = Todo('a'); + final todo2 = Todo('b'); + final todo3 = Todo('c', complete: true); + final model = TodoListModel( + filter: VisibilityFilter.completed, + repository: MockRepository(), + todos: [todo1, todo2, todo3], + ); + + expect(model.filteredTodos, [todo3]); + }, + ); test('should clear the completed todos', () async { final repository = MockRepository(); @@ -121,7 +121,7 @@ void main() { model.removeTodo(todo); - expect(model.todos, []); + expect(model.todos, []); expect(repository.saveCount, 1); }); @@ -148,7 +148,7 @@ void main() { final model = TodoListModel(repository: repository); expect(model.isLoading, isFalse); - expect(model.todos, []); + expect(model.todos, []); final loading = model.loadTodos(); diff --git a/change_notifier_provider/test_driver/integration_test.dart b/change_notifier_provider/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/change_notifier_provider/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/change_notifier_provider/test_driver/todo_app.dart b/change_notifier_provider/test_driver/todo_app.dart deleted file mode 100644 index 6436159b..00000000 --- a/change_notifier_provider/test_driver/todo_app.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// This line imports the extension -import 'package:flutter_driver/driver_extension.dart'; -import 'package:change_notifier_provider_sample/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/change_notifier_provider/test_driver/todo_app_test.dart b/change_notifier_provider/test_driver/todo_app_test.dart deleted file mode 100644 index fa00c88c..00000000 --- a/change_notifier_provider/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// _copyright 2018 _the _flutter _architecture _sample _authors. _all rights reserved. -// _use of this source code is governed by the _m_i_t license that can be found -// in the _l_i_c_e_n_s_e file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/change_notifier_provider/web/favicon.png b/change_notifier_provider/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/change_notifier_provider/web/favicon.png differ diff --git a/change_notifier_provider/web/icons/Icon-192.png b/change_notifier_provider/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/change_notifier_provider/web/icons/Icon-192.png differ diff --git a/change_notifier_provider/web/icons/Icon-512.png b/change_notifier_provider/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/change_notifier_provider/web/icons/Icon-512.png differ diff --git a/change_notifier_provider/web/icons/Icon-maskable-192.png b/change_notifier_provider/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/change_notifier_provider/web/icons/Icon-maskable-192.png differ diff --git a/change_notifier_provider/web/icons/Icon-maskable-512.png b/change_notifier_provider/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/change_notifier_provider/web/icons/Icon-maskable-512.png differ diff --git a/change_notifier_provider/web/index.html b/change_notifier_provider/web/index.html index 47bbc93b..39677907 100644 --- a/change_notifier_provider/web/index.html +++ b/change_notifier_provider/web/index.html @@ -1,10 +1,38 @@ + + + - change_notifier_provider + + + + + + + + + + + + + change_notifier_provider_sample + - + diff --git a/change_notifier_provider/web/manifest.json b/change_notifier_provider/web/manifest.json new file mode 100644 index 00000000..456cf19b --- /dev/null +++ b/change_notifier_provider/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "change_notifier_provider_sample", + "short_name": "change_notifier_provider_sample", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/change_notifier_provider/windows/.gitignore b/change_notifier_provider/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/change_notifier_provider/windows/.gitignore @@ -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/ diff --git a/change_notifier_provider/windows/CMakeLists.txt b/change_notifier_provider/windows/CMakeLists.txt new file mode 100644 index 00000000..177b62f3 --- /dev/null +++ b/change_notifier_provider/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(change_notifier_provider_sample 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 "change_notifier_provider_sample") + +# 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) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_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 "$") +# 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) diff --git a/change_notifier_provider/windows/flutter/CMakeLists.txt b/change_notifier_provider/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/change_notifier_provider/windows/flutter/CMakeLists.txt @@ -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} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/change_notifier_provider/windows/flutter/generated_plugin_registrant.cc b/change_notifier_provider/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/change_notifier_provider/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/change_notifier_provider/windows/flutter/generated_plugin_registrant.h b/change_notifier_provider/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/change_notifier_provider/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/change_notifier_provider/windows/flutter/generated_plugins.cmake b/change_notifier_provider/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/change_notifier_provider/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +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 $) + 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) diff --git a/change_notifier_provider/windows/runner/CMakeLists.txt b/change_notifier_provider/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/change_notifier_provider/windows/runner/CMakeLists.txt @@ -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) diff --git a/change_notifier_provider/windows/runner/Runner.rc b/change_notifier_provider/windows/runner/Runner.rc new file mode 100644 index 00000000..959154ce --- /dev/null +++ b/change_notifier_provider/windows/runner/Runner.rc @@ -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", "com.example" "\0" + VALUE "FileDescription", "change_notifier_provider_sample" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "change_notifier_provider_sample" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "change_notifier_provider_sample.exe" "\0" + VALUE "ProductName", "change_notifier_provider_sample" "\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 diff --git a/change_notifier_provider/windows/runner/flutter_window.cpp b/change_notifier_provider/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/change_notifier_provider/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#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( + 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 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); +} diff --git a/change_notifier_provider/windows/runner/flutter_window.h b/change_notifier_provider/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/change_notifier_provider/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#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_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/change_notifier_provider/windows/runner/main.cpp b/change_notifier_provider/windows/runner/main.cpp new file mode 100644 index 00000000..b2139b1b --- /dev/null +++ b/change_notifier_provider/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 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"change_notifier_provider_sample", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/change_notifier_provider/windows/runner/resource.h b/change_notifier_provider/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/change_notifier_provider/windows/runner/resource.h @@ -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 diff --git a/change_notifier_provider/windows/runner/resources/app_icon.ico b/change_notifier_provider/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/change_notifier_provider/windows/runner/resources/app_icon.ico differ diff --git a/change_notifier_provider/windows/runner/runner.exe.manifest b/change_notifier_provider/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/change_notifier_provider/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/change_notifier_provider/windows/runner/utils.cpp b/change_notifier_provider/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/change_notifier_provider/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +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 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::vector 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; +} diff --git a/change_notifier_provider/windows/runner/utils.h b/change_notifier_provider/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/change_notifier_provider/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// 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, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/change_notifier_provider/windows/runner/win32_window.cpp b/change_notifier_provider/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/change_notifier_provider/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#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(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( + 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(origin.x), + static_cast(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(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(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(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( + 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)); + } +} diff --git a/change_notifier_provider/windows/runner/win32_window.h b/change_notifier_provider/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/change_notifier_provider/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// 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_ diff --git a/firebase_flutter_repository/.flutter-plugins-dependencies b/firebase_flutter_repository/.flutter-plugins-dependencies deleted file mode 100644 index e3b89dcd..00000000 --- a/firebase_flutter_repository/.flutter-plugins-dependencies +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-0.13.1+1/","dependencies":["firebase_core"]},{"name":"firebase_auth","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/firebase_auth-0.15.4/","dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/firebase_core-0.4.3+3/","dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-0.13.1+1/","dependencies":["firebase_core"]},{"name":"firebase_auth","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/firebase_auth-0.15.4/","dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/firebase_core-0.4.3+3/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[{"name":"firebase_auth_web","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/firebase_auth_web-0.1.2/","dependencies":[]},{"name":"firebase_core_web","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.1.1+2/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["firebase_core"]},{"name":"firebase_auth","dependencies":["firebase_core","firebase_auth_web"]},{"name":"firebase_auth_web","dependencies":[]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]}],"date_created":"2020-02-10 11:23:47.330621","version":"1.14.7-pre.38"} \ No newline at end of file diff --git a/firebase_flutter_repository/README.md b/firebase_flutter_repository/README.md deleted file mode 100644 index 3ecb0eca..00000000 --- a/firebase_flutter_repository/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# firebase_flutter_repository - -A reactive version of the todos repository and user repository backed by Firestore and FirebaseAuth for Flutter. - -## Defines how to log in - -This library provides a concrete implementation of the `UserRepository` class. It uses the `firebase_auth` package and anonymous login as the mechanism and returns a `UserEntity`. - -## Defines how to interact with Todos - -This library provides a concrete implementation of the `ReactiveTodosRepository`. - -To listen for real-time changes, it streams `TodoEntity` objects stored in the `todos` collection on Firestore. To create, update, and delete todos, it pushes changes to the `todos` collection or individual documents. diff --git a/firebase_flutter_repository/lib/reactive_todos_repository.dart b/firebase_flutter_repository/lib/reactive_todos_repository.dart deleted file mode 100644 index 6936f5f0..00000000 --- a/firebase_flutter_repository/lib/reactive_todos_repository.dart +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -class FirestoreReactiveTodosRepository implements ReactiveTodosRepository { - static const String path = 'todo'; - - final Firestore firestore; - - const FirestoreReactiveTodosRepository(this.firestore); - - @override - Future addNewTodo(TodoEntity todo) { - return firestore.collection(path).document(todo.id).setData(todo.toJson()); - } - - @override - Future deleteTodo(List idList) async { - await Future.wait(idList.map((id) { - return firestore.collection(path).document(id).delete(); - })); - } - - @override - Stream> todos() { - return firestore.collection(path).snapshots().map((snapshot) { - return snapshot.documents.map((doc) { - return TodoEntity( - doc['task'], - doc.documentID, - doc['note'] ?? '', - doc['complete'] ?? false, - ); - }).toList(); - }); - } - - @override - Future updateTodo(TodoEntity todo) { - return firestore - .collection(path) - .document(todo.id) - .updateData(todo.toJson()); - } -} diff --git a/firebase_flutter_repository/lib/user_repository.dart b/firebase_flutter_repository/lib/user_repository.dart deleted file mode 100644 index cbf0d932..00000000 --- a/firebase_flutter_repository/lib/user_repository.dart +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -class FirebaseUserRepository implements UserRepository { - final FirebaseAuth auth; - - const FirebaseUserRepository(this.auth); - - @override - Future login() async { - final firebaseUser = await auth.signInAnonymously(); - - return UserEntity( - id: firebaseUser.user.uid, - displayName: firebaseUser.user.displayName, - photoUrl: firebaseUser.user.photoUrl, - ); - } -} diff --git a/firebase_flutter_repository/pubspec.yaml b/firebase_flutter_repository/pubspec.yaml deleted file mode 100644 index 3f812f9a..00000000 --- a/firebase_flutter_repository/pubspec.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: firebase_flutter_repository -description: A reactive version of the todos repository for Flutter - -environment: - sdk: '>=2.0.0 <3.0.0' - -dependencies: - flutter: - sdk: flutter - todos_repository_core: - path: ../todos_repository_core - firebase_auth: ^0.15.3 - cloud_firestore: ^0.13.0+1 - -dev_dependencies: - test: - mockito: - flutter_test: - sdk: flutter - -flutter: diff --git a/firebase_flutter_repository/test/firebase_flutter_repository_test.dart b/firebase_flutter_repository/test/firebase_flutter_repository_test.dart deleted file mode 100644 index 2023577e..00000000 --- a/firebase_flutter_repository/test/firebase_flutter_repository_test.dart +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:firebase_flutter_repository/reactive_todos_repository.dart'; -import 'package:firebase_flutter_repository/user_repository.dart'; -import 'package:mockito/mockito.dart'; -import 'package:test/test.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -void main() { - group('FirebaseUserRepository', () { - test('should log the user in anonymously', () async { - final auth = MockFirebaseAuth(); - final repository = FirebaseUserRepository(auth); - - when(auth.signInAnonymously()) - .thenAnswer((_) => Future.value(MockAuthResult())); - - final entity = await repository.login(); - - expect(entity, TypeMatcher()); - }); - }); - - group('FirebaseReactiveTodosRepository', () { - test('should send todos to firestore', () { - final firestore = MockFirestore(); - final collection = MockCollectionReference(); - final document = MockDocumentReference(); - final repository = FirestoreReactiveTodosRepository(firestore); - final todo = TodoEntity('A', '1', '', true); - - when(firestore.collection(FirestoreReactiveTodosRepository.path)) - .thenReturn(collection); - when(collection.document(todo.id)).thenReturn(document); - - repository.addNewTodo(todo); - - verify(document.setData(todo.toJson())); - }); - - test('should update todos on firestore', () { - final firestore = MockFirestore(); - final collection = MockCollectionReference(); - final document = MockDocumentReference(); - final repository = FirestoreReactiveTodosRepository(firestore); - final todo = TodoEntity('A', '1', '', true); - - when(firestore.collection(FirestoreReactiveTodosRepository.path)) - .thenReturn(collection); - when(collection.document(todo.id)).thenReturn(document); - - repository.updateTodo(todo); - - verify(document.updateData(todo.toJson())); - }); - - test('should listen for updates to the collection', () { - final todo = TodoEntity('A', '1', '', true); - final firestore = MockFirestore(); - final collection = MockCollectionReference(); - final snapshot = MockQuerySnapshot(); - final snapshots = Stream.fromIterable([snapshot]); - final document = MockDocumentSnapshot(todo.toJson()); - final repository = FirestoreReactiveTodosRepository(firestore); - - when(firestore.collection(FirestoreReactiveTodosRepository.path)) - .thenReturn(collection); - when(collection.snapshots()).thenAnswer((_) => snapshots); - when(snapshot.documents).thenReturn([document]); - when(document.documentID).thenReturn(todo.id); - - expect(repository.todos(), emits([todo])); - }); - - test('should delete todos on firestore', () async { - final todoA = 'A'; - final todoB = 'B'; - final firestore = MockFirestore(); - final collection = MockCollectionReference(); - final documentA = MockDocumentReference(); - final documentB = MockDocumentReference(); - final repository = FirestoreReactiveTodosRepository(firestore); - - when(firestore.collection(FirestoreReactiveTodosRepository.path)) - .thenReturn(collection); - when(collection.document(todoA)).thenReturn(documentA); - when(collection.document(todoB)).thenReturn(documentB); - when(documentA.delete()).thenAnswer((_) => Future.value()); - when(documentB.delete()).thenAnswer((_) => Future.value()); - - await repository.deleteTodo([todoA, todoB]); - - verify(documentA.delete()); - verify(documentB.delete()); - }); - }); -} - -class MockFirebaseAuth extends Mock implements FirebaseAuth {} - -class MockFirestore extends Mock implements Firestore {} - -class MockCollectionReference extends Mock implements CollectionReference {} - -class MockDocumentSnapshot extends Mock implements DocumentSnapshot { - @override - final Map data; - - MockDocumentSnapshot([this.data]); - - @override - dynamic operator [](String key) => data[key]; -} - -class MockDocumentReference extends Mock implements DocumentReference {} - -class MockQuerySnapshot extends Mock implements QuerySnapshot {} - -class MockAuthResult extends Mock implements AuthResult { - @override - final user = MockFirebaseUser(); -} - -class MockFirebaseUser extends Mock implements FirebaseUser {} diff --git a/firebase_rtdb_flutter_repository/README.md b/firebase_rtdb_flutter_repository/README.md deleted file mode 100644 index 64da2608..00000000 --- a/firebase_rtdb_flutter_repository/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# firebase_rtdb_flutter_repository - -A reactive version of the todos repository and user repository backed by Firebase Realtime Database -and FirebaseAuth for Flutter. - -## Defines how to log in - -This library provides a concrete implementation of the `UserRepository` class. It uses the `firebase_auth` package and anonymous login as the mechanism and returns a `UserEntity`. - -## Defines how to interact with Todos - -This library provides a concrete implementation of the `ReactiveTodosRepository`. - -To listen for real-time changes, it streams `TodoEntity` objects stored in the `todos` collection on - Firebase Realtime Database. To create, update, and delete todos, it pushes changes to the `todos` - collection or individual documents. - -### Works with `firestore_redux` project - -In `main.dart` replace the current implementation of the abstract `ReactiveTodosRepository` -```dart - FirestoreReactiveTodosRepository(Firestore.instance) -``` -with -```dart - FirebaseReactiveTodosRepository(FirebaseDatabase.instance) -``` -Also in `main.dart` replace the `cloud_firestore` package with the `firebase_database` package. Replace -```dart -import 'package:cloud_firestore/cloud_firestore.dart'; -``` -with -```dart -import 'package:firebase_database/firebase_database.dart'; -``` -In `pubspec.yaml` replace -```yaml - firebase_flutter_repository: - path: ../firebase_flutter_repository -``` -with -```yaml - firebase_flutter_repository: - path: ../firebase_rtdb_flutter_repository -``` - -Then update packages from commandline with -``` -flutter packages get -``` -or the equivalent with your IDE. diff --git a/firebase_rtdb_flutter_repository/lib/reactive_todos_repository.dart b/firebase_rtdb_flutter_repository/lib/reactive_todos_repository.dart deleted file mode 100644 index 8b779050..00000000 --- a/firebase_rtdb_flutter_repository/lib/reactive_todos_repository.dart +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:firebase_database/firebase_database.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -class FirebaseReactiveTodosRepository implements ReactiveTodosRepository { - static const String path = 'todo'; - - final FirebaseDatabase firebase; - - const FirebaseReactiveTodosRepository(this.firebase); - - @override - Future addNewTodo(TodoEntity todo) { - return updateTodo(todo); - } - - @override - Future deleteTodo(List idList) async { - await Future.wait(idList.map((id) { - return firebase.reference().child(path).child(id).set(null); - })); - } - - @override - Stream> todos() { - return firebase.reference().child(path).onValue.map((event) { - if (event.snapshot == null || event.snapshot.value == null) return []; - final Map value = event.snapshot.value; - final todoMap = value.map((key, doc) { - return MapEntry( - key, - TodoEntity( - doc['task'], - key, - doc['note'] ?? '', - doc['complete'] ?? false, - )); - }); - return todoMap.values.toList(); - }); - } - - @override - Future updateTodo(TodoEntity todo) { - return firebase.reference().child(path).child(todo.id).set(todo.toJson()); - } -} diff --git a/firebase_rtdb_flutter_repository/lib/user_repository.dart b/firebase_rtdb_flutter_repository/lib/user_repository.dart deleted file mode 100644 index caafe548..00000000 --- a/firebase_rtdb_flutter_repository/lib/user_repository.dart +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -class FirebaseUserRepository implements UserRepository { - final FirebaseAuth auth; - - const FirebaseUserRepository(this.auth); - - @override - Future login() async { - final firebaseUser = await auth.signInAnonymously(); - - return UserEntity( - id: firebaseUser.uid, - displayName: firebaseUser.displayName, - photoUrl: firebaseUser.photoUrl, - ); - } -} diff --git a/firebase_rtdb_flutter_repository/pubspec.yaml b/firebase_rtdb_flutter_repository/pubspec.yaml deleted file mode 100644 index 11e4c493..00000000 --- a/firebase_rtdb_flutter_repository/pubspec.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: firebase_flutter_repository -description: A reactive version of the todos repository for Flutter using Firebase Realtime Database - -environment: - sdk: '>=2.0.0 <3.0.0' - -dependencies: - flutter: - sdk: flutter - todos_repository_core: - path: ../todos_repository_core - firebase_auth: 0.5.9 - firebase_database: ^3.1.1 - -dev_dependencies: - test: - mockito: - flutter_test: - sdk: flutter diff --git a/firebase_rtdb_flutter_repository/test/firebase_flutter_repository_test.dart b/firebase_rtdb_flutter_repository/test/firebase_flutter_repository_test.dart deleted file mode 100644 index 66f8eae1..00000000 --- a/firebase_rtdb_flutter_repository/test/firebase_flutter_repository_test.dart +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:firebase_database/firebase_database.dart'; -import 'package:firebase_flutter_repository/reactive_todos_repository.dart'; -import 'package:firebase_flutter_repository/user_repository.dart'; -import 'package:mockito/mockito.dart'; -import 'package:test/test.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -void main() { - group('FirebaseUserRepository', () { - test('should log the user in anonymously', () async { - final auth = MockFirebaseAuth(); - final repository = FirebaseUserRepository(auth); - - when(auth.signInAnonymously()) - .thenAnswer((_) => Future.value(MockFirebaseUser())); - - final entity = await repository.login(); - - expect(entity, TypeMatcher()); - }); - }); - - group('FirebaseReactiveTodosRepository', () { - test('should send todos to firebase database', () { - final firebaseDatabase = MockFirebaseDatabase(); - final reference = MockDatabaseReference(); - final collection = MockDatabaseReference(); - final document = MockDatabaseReference(); - final repository = FirebaseReactiveTodosRepository(firebaseDatabase); - final todo = TodoEntity('A', '1', '', true); - - when(firebaseDatabase.reference()).thenReturn(reference); - when(reference.child(FirebaseReactiveTodosRepository.path)) - .thenReturn(collection); - when(collection.child(todo.id)).thenReturn(document); - - repository.addNewTodo(todo); - - verify(document.set(todo.toJson())); - }); - - test('should update todos on firebase database', () { - final firebaseDatabase = MockFirebaseDatabase(); - final reference = MockDatabaseReference(); - final collection = MockDatabaseReference(); - final document = MockDatabaseReference(); - final repository = FirebaseReactiveTodosRepository(firebaseDatabase); - final todo = TodoEntity('A', '1', '', true); - - when(firebaseDatabase.reference()).thenReturn(reference); - when(reference.child(FirebaseReactiveTodosRepository.path)) - .thenReturn(collection); - when(collection.child(todo.id)).thenReturn(document); - - repository.updateTodo(todo); - - verify(document.set(todo.toJson())); - }); - - test('should listen for updates to the collection', () { - final todo = TodoEntity('A', '1', '', true); - final firebaseDatabase = MockFirebaseDatabase(); - final reference = MockDatabaseReference(); - final collection = MockDatabaseReference(); - final document = todo.toJson(); - final documentMap = {todo.id: document}; - final event = MockEvent(); - final eventIterator = Stream.fromIterable([event]); - final data = {'key': todo.id, 'value': documentMap}; - final snapshot = MockDataSnapshot(data); - final repository = FirebaseReactiveTodosRepository(firebaseDatabase); - - when(firebaseDatabase.reference()).thenReturn(reference); - when(reference.child(FirebaseReactiveTodosRepository.path)) - .thenReturn(collection); - when(collection.onValue).thenAnswer((_) => eventIterator); - when(event.snapshot).thenReturn(snapshot); - when(snapshot.key).thenReturn(todo.id); // not used - when(snapshot.value).thenReturn(documentMap); - - expect(repository.todos(), emits([todo])); - }); - - test('should delete todos on firebaseDatabase', () async { - final todoA = 'A'; - final todoB = 'B'; - final firebaseDatabase = MockFirebaseDatabase(); - final reference = MockDatabaseReference(); - final collection = MockDatabaseReference(); - final documentA = MockDatabaseReference(); - final documentB = MockDatabaseReference(); - final repository = FirebaseReactiveTodosRepository(firebaseDatabase); - - when(firebaseDatabase.reference()).thenReturn(reference); - when(reference.child(FirebaseReactiveTodosRepository.path)) - .thenReturn(collection); - when(collection.child(todoA)).thenReturn(documentA); - when(collection.child(todoB)).thenReturn(documentB); - when(documentA.set(null)).thenAnswer((_) => Future.value()); - when(documentB.set(null)).thenAnswer((_) => Future.value()); - - await repository.deleteTodo([todoA, todoB]); - - verify(documentA.set(null)); - verify(documentB.set(null)); - }); - }); -} - -class MockFirebaseAuth extends Mock implements FirebaseAuth {} - -class MockFirebaseDatabase extends Mock implements FirebaseDatabase {} - -class MockDatabaseReference extends Mock implements DatabaseReference {} - -class MockEvent extends Mock implements Event {} - -class MockDataSnapshot extends Mock implements DataSnapshot { - final Map data; - - MockDataSnapshot([this.data]); -} - -class MockFirebaseUser extends Mock implements FirebaseUser {} diff --git a/firestore_redux/.flutter-plugins-dependencies b/firestore_redux/.flutter-plugins-dependencies deleted file mode 100644 index ba421a8f..00000000 --- a/firestore_redux/.flutter-plugins-dependencies +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-0.13.1+1/","dependencies":["firebase_core"]},{"name":"firebase_auth","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/firebase_auth-0.15.4/","dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/firebase_core-0.4.3+3/","dependencies":[]},{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-0.13.1+1/","dependencies":["firebase_core"]},{"name":"firebase_auth","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/firebase_auth-0.15.4/","dependencies":["firebase_core"]},{"name":"firebase_core","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/firebase_core-0.4.3+3/","dependencies":[]},{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[{"name":"firebase_auth_web","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/firebase_auth_web-0.1.2/","dependencies":[]},{"name":"firebase_core_web","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.1.1+2/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["firebase_core"]},{"name":"firebase_auth","dependencies":["firebase_core","firebase_auth_web"]},{"name":"firebase_auth_web","dependencies":[]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"path_provider","dependencies":[]}],"date_created":"2020-02-10 11:23:57.149758","version":"1.14.7-pre.38"} \ No newline at end of file diff --git a/firestore_redux/.gitignore b/firestore_redux/.gitignore deleted file mode 100644 index 2ddde2a5..00000000 --- a/firestore_redux/.gitignore +++ /dev/null @@ -1,73 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# 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 -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.packages -.pub-cache/ -.pub/ -/build/ - -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/firestore_redux/.metadata b/firestore_redux/.metadata deleted file mode 100644 index 1b5cec02..00000000 --- a/firestore_redux/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 27321ebbad34b0a3fafe99fac037102196d655ff - channel: stable - -project_type: app diff --git a/firestore_redux/README.md b/firestore_redux/README.md deleted file mode 100644 index f40e2cb9..00000000 --- a/firestore_redux/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# firestore redux sample - -This repo started with [flutter_architecture_redux sample](https://github.com/brianegan/flutter_architecture_samples/blob/master/redux/README.md), -and added [Cloud_Firestore](https://firebase.google.com/docs/firestore/) as the backend database. Cloud Firestore -provides realtime connection between the database and authenticated devices, as well as automatic offline -persistence for Android and iOS. Firebase authentication is included for anonymous authentication of users. - -## Set-up - -The steps below were primarily developed from [MemeChat repo](https://github.com/efortuna/memechat/blob/master/README.md). -There is a very useful [video tutorial](https://www.youtube.com/watch?v=w2TcYP8qiRI) associated with the MemeChat -repo from 2017 Google I/O that covers some basics related to connecting to Firebase. Additionally, refer to -[Firebase for Flutter Codelab](https://codelabs.developers.google.com/codelabs/flutter-firebase/index.html?index=..%2F..%2Findex#0) -In the present case, Firestore is being used but set up is similar. - -1) Set up a Firestore instance at [Firebase Console](https://console.firebase.google.com/). - -2) Enable anonymous authentication by going to 'Authentication' in left hand menu, selecting -'Sign-in Method', and enabling Anonymous at the bottom of the page. - -3) For Android: - - - Create an app within your Firebase instance for Android, with package name com.yourcompany.fireredux. - In the Firebase console, in the settings of your Android app, add your SHA-1 key by clicking "Add Fingerprint". - Run the following command to get your SHA-1 key: - - `keytool -exportcert -list -v -alias androiddebugkey -keystore ~/.android/debug.keystore` - - Follow instructions to download google-services.json, and place it into fire_redux/android/app/. - - Set the defaultConfig.applicationID in `android/app/build.gradle` to match - android_client_info.package_name in `google-services.json`, e.g. `com.yourcompany.fireredux`. - This is the name of your Android app in Firebase. - Package values must match between files `android/app/src/main/AndroidManifest.xml` and - `android/app/src/main/java/yourcompany/redux/MainActivity.java`, e.g. `com.yourcompany.fireredux`. - - - To connect to Firestore be sure your project is using Gradle 4.1 and Android Studio Gradle plugin 3.0.1. - If you are creating a new Flutter project, then this should already be set up properly. - If not, then follow these - [upgrades steps](https://github.com/flutter/flutter/wiki/Updating-Flutter-projects-to-Gradle-4.1-and-Android-Studio-Gradle-plugin-3.0.1). - You will need to edit these files: `android/gradle/wrapper/gradle-wrapper.properties`, - `android/build.gradle`, and `android/app/build.gradle`. - - - Add google-service plugin to `android/build.gradle` under buildscript.dependencies: - - `classpath 'com.google.gms:google-services:3.1.0'`. - - - Apply this plugin to `android/app/build.gradle` by adding this to the end of the file: - - `apply plugin: 'com.google.gms.google-services'` - - - Add the following to `android/build.gradle` under allprojects.repositories: - - ` maven { - url "https://jitpack.io" - }` - -4) For iOS: - - - Create an app within your Firebase instance for iOS, with package name com.yourcompany.fireredux. - - Follow instructions to download GoogleService-Info.plist, and place it into fire_redux/ios/Runner. - - Open fire_redux/ios/Runner/Info.plist. Locate the CFBundleURLSchemes key. - The second item in the array value of this key is specific to the Firebase instance. - Replace it with the value for REVERSED_CLIENT_ID from GoogleService-Info.plist. It will look like this: - ```$xslt - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLSchemes - - com.yourcompany.firereduxios - com.googleusercontent.apps.631911544122-jtjdk7lmrqoiup15hofsceegpfn0dhj6 - - - - ``` - - To successfully run on iOS, it may be necessary to manually copy GoogleService-Info.plist - to your Xcode project. After you attempt a run/build of your project on iOS open Xcode by - clicking on fire_redux/ios/Runner.xcworkspace. When your project is open in Xcode, then copy - GoogleService-Info.plist to Runner/Runner folder. Then your project should run on iOS. - - -## Summary of changes made to the original redux sample repo. - - 1. Added `firebase_flutter_repository` to the `pubspec.yaml`, removed `todos_repository_simple`. - 2. Limit the responsibility of the Reducers since Firestore is the source of truth. - 3. Change the Middleware to work with a `UserRepository` for auth and `ReactiveTodosRepository` to listen for changes to the Todos and push updates to Firestore. - 4. Add Actions for Login and to Start Listening to Firestore. It's not needed in this app, but we could also add an action to stop listening to Firestore. - -## Testing - -For integration testing, we need to pass through a Mock `UserRepository` and Mock `ReactiveTodosRepository`. - - 1. `flutter test` will run all unit tests. - * `flutter test test/selectors_test.dart` for selectors unit testing. - * `flutter test test/reducer_test.dart` for reducers unit testing. - * `flutter test test/middleware_test.dart` for middleware unit testing. - 2. `flutter drive --target=test_driver/todo_app.dart` to run integrations test. Integrations tests are unchanged from the original redux repo. diff --git a/firestore_redux/android/.gitignore b/firestore_redux/android/.gitignore deleted file mode 100644 index bc2100d8..00000000 --- a/firestore_redux/android/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java diff --git a/firestore_redux/android/app/build.gradle b/firestore_redux/android/app/build.gradle deleted file mode 100644 index e449cb88..00000000 --- a/firestore_redux/android/app/build.gradle +++ /dev/null @@ -1,68 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.firestore_redux" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - multiDexEnabled true - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/firestore_redux/android/app/src/debug/AndroidManifest.xml b/firestore_redux/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index c30df743..00000000 --- a/firestore_redux/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/firestore_redux/android/app/src/main/AndroidManifest.xml b/firestore_redux/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index a6e1e1bf..00000000 --- a/firestore_redux/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - diff --git a/firestore_redux/android/app/src/main/kotlin/com/example/firestore_redux/MainActivity.kt b/firestore_redux/android/app/src/main/kotlin/com/example/firestore_redux/MainActivity.kt deleted file mode 100644 index a7de940a..00000000 --- a/firestore_redux/android/app/src/main/kotlin/com/example/firestore_redux/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.firestore_redux - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/firestore_redux/android/app/src/main/res/drawable/launch_background.xml b/firestore_redux/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/firestore_redux/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/firestore_redux/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/firestore_redux/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index a3f285f9..00000000 Binary files a/firestore_redux/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/firestore_redux/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/firestore_redux/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 5e6f3ac6..00000000 Binary files a/firestore_redux/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/firestore_redux/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/firestore_redux/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 144d60be..00000000 Binary files a/firestore_redux/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/firestore_redux/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/firestore_redux/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index deafae2d..00000000 Binary files a/firestore_redux/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/firestore_redux/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/firestore_redux/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index d5614ac8..00000000 Binary files a/firestore_redux/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/firestore_redux/android/app/src/main/res/values/styles.xml b/firestore_redux/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 00fa4417..00000000 --- a/firestore_redux/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/firestore_redux/android/app/src/profile/AndroidManifest.xml b/firestore_redux/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index c30df743..00000000 --- a/firestore_redux/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/firestore_redux/android/build.gradle b/firestore_redux/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/firestore_redux/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/firestore_redux/android/gradle.properties b/firestore_redux/android/gradle.properties deleted file mode 100644 index 38c8d454..00000000 --- a/firestore_redux/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true -android.useAndroidX=true -android.enableJetifier=true diff --git a/firestore_redux/android/gradle/wrapper/gradle-wrapper.properties b/firestore_redux/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 296b146b..00000000 --- a/firestore_redux/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/firestore_redux/android/settings.gradle b/firestore_redux/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/firestore_redux/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/firestore_redux/ios/.gitignore b/firestore_redux/ios/.gitignore deleted file mode 100644 index e96ef602..00000000 --- a/firestore_redux/ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/firestore_redux/ios/Flutter/AppFrameworkInfo.plist b/firestore_redux/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6b4c0f78..00000000 --- a/firestore_redux/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/firestore_redux/ios/Flutter/Debug.xcconfig b/firestore_redux/ios/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba11..00000000 --- a/firestore_redux/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/firestore_redux/ios/Flutter/Release.xcconfig b/firestore_redux/ios/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340..00000000 --- a/firestore_redux/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/firestore_redux/ios/Podfile b/firestore_redux/ios/Podfile deleted file mode 100644 index b30a428b..00000000 --- a/firestore_redux/ios/Podfile +++ /dev/null @@ -1,90 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '9.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; - end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end - end - generated_key_values -end - -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; - - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' - - # Plugin Pods - - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') - end -end - -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - -post_install do |installer| - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end - end -end diff --git a/firestore_redux/ios/Runner.xcodeproj/project.pbxproj b/firestore_redux/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 7eaece8c..00000000 --- a/firestore_redux/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,588 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3DC6C12F0C8DFDEB46BBFD03 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A9BD3573C89AFE68E3A21F6 /* Pods_Runner.framework */; }; - 4EEE3E9123C493B90065A5A2 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4EEE3E9023C493B80065A5A2 /* GoogleService-Info.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 32DF067C14C43DCE0F4AD703 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 3A9BD3573C89AFE68E3A21F6 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 4EEE3E9023C493B80065A5A2 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 8C698F6ECF0154F865792E58 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9E51BC1BAB575DF40A23CCE8 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - 3DC6C12F0C8DFDEB46BBFD03 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 14C49F13D6D71163E2B1EDBD /* Frameworks */ = { - isa = PBXGroup; - children = ( - 3A9BD3573C89AFE68E3A21F6 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 6535F9FC413878FBAB23E085 /* Pods */ = { - isa = PBXGroup; - children = ( - 8C698F6ECF0154F865792E58 /* Pods-Runner.debug.xcconfig */, - 32DF067C14C43DCE0F4AD703 /* Pods-Runner.release.xcconfig */, - 9E51BC1BAB575DF40A23CCE8 /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 6535F9FC413878FBAB23E085 /* Pods */, - 14C49F13D6D71163E2B1EDBD /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 4EEE3E9023C493B80065A5A2 /* GoogleService-Info.plist */, - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - DA25481C73BA8ED396688A6A /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 733B60DD2D2D2F65ABD9C4F3 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 4EEE3E9123C493B90065A5A2 /* GoogleService-Info.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 733B60DD2D2D2F65ABD9C4F3 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - DA25481C73BA8ED396688A6A /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.firestoreRedux; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.firestoreRedux; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.firestoreRedux; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/firestore_redux/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/firestore_redux/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/firestore_redux/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/firestore_redux/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/firestore_redux/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140cf..00000000 --- a/firestore_redux/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/firestore_redux/ios/Runner/AppDelegate.swift b/firestore_redux/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a..00000000 --- a/firestore_redux/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d22f10b2..00000000 --- a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 980e5ad6..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index fd870289..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 75e84cd1..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 03ab8a84..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index a03431cb..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index f47613ee..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 7f2230a9..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 42315c6d..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index f9882cc0..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 45537513..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 6360ea17..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 152d5e12..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 310b0b8f..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 092b7bfe..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2f..00000000 --- a/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/firestore_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -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. \ No newline at end of file diff --git a/firestore_redux/ios/Runner/Base.lproj/LaunchScreen.storyboard b/firestore_redux/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/firestore_redux/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/firestore_redux/ios/Runner/Base.lproj/Main.storyboard b/firestore_redux/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/firestore_redux/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/firestore_redux/ios/Runner/GoogleService-Info.plist b/firestore_redux/ios/Runner/GoogleService-Info.plist deleted file mode 100644 index c8cc9bf9..00000000 --- a/firestore_redux/ios/Runner/GoogleService-Info.plist +++ /dev/null @@ -1,40 +0,0 @@ - - - - - AD_UNIT_ID_FOR_BANNER_TEST - ca-app-pub-9999999999999999/9999999999 - AD_UNIT_ID_FOR_INTERSTITIAL_TEST - ca-app-pub-9999999999999999/9999999999 - CLIENT_ID - xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com - REVERSED_CLIENT_ID - com.googleusercontent.apps.xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - API_KEY - xxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx - GCM_SENDER_ID - 999999999999 - PLIST_VERSION - 1 - BUNDLE_ID - com.fluttersamples.bloc - PROJECT_ID - xxxxxxxxxxxxx-99999 - STORAGE_BUCKET - xxxxxxxxxxxxx-99999.appspot.com - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 9:999999999999:ios:xxxxxxxxxxxxxxxx - DATABASE_URL - https://xxxxxxxxxxxxx-99999.firebaseio.com - - \ No newline at end of file diff --git a/firestore_redux/ios/Runner/Info.plist b/firestore_redux/ios/Runner/Info.plist deleted file mode 100644 index 4572c6e7..00000000 --- a/firestore_redux/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - firestore_redux - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/firestore_redux/ios/Runner/Runner-Bridging-Header.h b/firestore_redux/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 7335fdf9..00000000 --- a/firestore_redux/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file diff --git a/firestore_redux/lib/actions/actions.dart b/firestore_redux/lib/actions/actions.dart deleted file mode 100644 index d39373b5..00000000 --- a/firestore_redux/lib/actions/actions.dart +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/models/visibility_filter.dart'; - -class ClearCompletedAction {} - -class ToggleAllAction { - ToggleAllAction(); - - @override - String toString() { - return 'ToggleAllAction{}'; - } -} - -class LoadTodosAction { - final List todos; - - LoadTodosAction(this.todos); - - @override - String toString() { - return 'LoadTodosAction{todos: $todos}'; - } -} - -class UpdateTodoAction { - final String id; - final Todo updatedTodo; - - UpdateTodoAction(this.id, this.updatedTodo); - - @override - String toString() { - return 'UpdateTodoAction{id: $id, updatedTodo: $updatedTodo}'; - } -} - -class DeleteTodoAction { - final String id; - - DeleteTodoAction(this.id); - - @override - String toString() { - return 'DeleteTodoAction{id: $id}'; - } -} - -class AddTodoAction { - final Todo todo; - - AddTodoAction(this.todo); - - @override - String toString() { - return 'AddTodoAction{todo: $todo}'; - } -} - -class InitAppAction { - @override - String toString() { - return 'InitAppAction{}'; - } -} - -class ConnectToDataSourceAction { - @override - String toString() { - return 'ConnectToDataSourceAction{}'; - } -} - -class UpdateFilterAction { - final VisibilityFilter newFilter; - - UpdateFilterAction(this.newFilter); - - @override - String toString() { - return 'UpdateFilterAction{newFilter: $newFilter}'; - } -} - -class UpdateTabAction { - final AppTab newTab; - - UpdateTabAction(this.newTab); - - @override - String toString() { - return 'UpdateTabAction{newTab: $newTab}'; - } -} diff --git a/firestore_redux/lib/containers/active_tab.dart b/firestore_redux/lib/containers/active_tab.dart deleted file mode 100644 index 5baa1670..00000000 --- a/firestore_redux/lib/containers/active_tab.dart +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -class ActiveTab extends StatelessWidget { - final ViewModelBuilder builder; - - ActiveTab({Key key, @required this.builder}) : super(key: key); - - @override - Widget build(BuildContext context) { - return StoreConnector( - distinct: true, - converter: (Store store) => store.state.activeTab, - builder: builder, - ); - } -} diff --git a/firestore_redux/lib/containers/add_todo.dart b/firestore_redux/lib/containers/add_todo.dart deleted file mode 100644 index c9734717..00000000 --- a/firestore_redux/lib/containers/add_todo.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/presentation/add_edit_screen.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -class AddTodo extends StatelessWidget { - AddTodo({Key key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return StoreConnector( - converter: (Store store) { - return (task, note) { - store.dispatch(AddTodoAction(Todo( - task, - note: note, - ))); - }; - }, - builder: (BuildContext context, OnSaveCallback onSave) { - return AddEditScreen( - key: ArchSampleKeys.addTodoScreen, - onSave: onSave, - isEditing: false, - ); - }, - ); - } -} diff --git a/firestore_redux/lib/containers/app_loading.dart b/firestore_redux/lib/containers/app_loading.dart deleted file mode 100644 index 1bedc179..00000000 --- a/firestore_redux/lib/containers/app_loading.dart +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/selectors/selectors.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -class AppLoading extends StatelessWidget { - final Function(BuildContext context, bool isLoading) builder; - - AppLoading({Key key, @required this.builder}) : super(key: key); - - @override - Widget build(BuildContext context) { - return StoreConnector( - distinct: true, - converter: (Store store) => isLoadingSelector(store.state), - builder: builder, - ); - } -} diff --git a/firestore_redux/lib/containers/edit_todo.dart b/firestore_redux/lib/containers/edit_todo.dart deleted file mode 100644 index 315ec633..00000000 --- a/firestore_redux/lib/containers/edit_todo.dart +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/presentation/add_edit_screen.dart'; -import 'package:flutter/widgets.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -class EditTodo extends StatelessWidget { - final Todo todo; - - EditTodo({this.todo, Key key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return StoreConnector( - converter: (Store store) { - return (task, note) { - store.dispatch(UpdateTodoAction( - todo.id, - todo.copyWith( - task: task, - note: note, - ), - )); - }; - }, - builder: (BuildContext context, OnSaveCallback onSave) { - return AddEditScreen( - key: ArchSampleKeys.editTodoScreen, - onSave: onSave, - isEditing: true, - todo: todo, - ); - }, - ); - } -} diff --git a/firestore_redux/lib/containers/extra_actions_container.dart b/firestore_redux/lib/containers/extra_actions_container.dart deleted file mode 100644 index 057a6132..00000000 --- a/firestore_redux/lib/containers/extra_actions_container.dart +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/presentation/extra_actions_button.dart'; -import 'package:fire_redux_sample/selectors/selectors.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -class ExtraActionsContainer extends StatelessWidget { - ExtraActionsContainer({Key key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return StoreConnector( - distinct: true, - converter: _ViewModel.fromStore, - builder: (context, vm) { - return ExtraActionsButton( - allComplete: vm.allComplete, - onSelected: vm.onActionSelected, - ); - }, - ); - } -} - -class _ViewModel { - final Function(ExtraAction) onActionSelected; - final bool allComplete; - - _ViewModel({ - @required this.onActionSelected, - @required this.allComplete, - }); - - static _ViewModel fromStore(Store store) { - return _ViewModel( - onActionSelected: (action) { - if (action == ExtraAction.clearCompleted) { - store.dispatch(ClearCompletedAction()); - } else if (action == ExtraAction.toggleAllComplete) { - store.dispatch(ToggleAllAction()); - } - }, - allComplete: allCompleteSelector(todosSelector(store.state)), - ); - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is _ViewModel && - runtimeType == other.runtimeType && - allComplete == other.allComplete; - - @override - int get hashCode => allComplete.hashCode; -} diff --git a/firestore_redux/lib/containers/filter_selector.dart b/firestore_redux/lib/containers/filter_selector.dart deleted file mode 100644 index 839842f9..00000000 --- a/firestore_redux/lib/containers/filter_selector.dart +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/presentation/filter_button.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -class FilterSelector extends StatelessWidget { - final bool visible; - - FilterSelector({Key key, @required this.visible}) : super(key: key); - - @override - Widget build(BuildContext context) { - return StoreConnector( - distinct: true, - converter: _ViewModel.fromStore, - builder: (context, vm) { - return FilterButton( - visible: visible, - activeFilter: vm.activeFilter, - onSelected: vm.onFilterSelected, - ); - }, - ); - } -} - -class _ViewModel { - final Function(VisibilityFilter) onFilterSelected; - final VisibilityFilter activeFilter; - - _ViewModel({ - @required this.onFilterSelected, - @required this.activeFilter, - }); - - static _ViewModel fromStore(Store store) { - return _ViewModel( - onFilterSelected: (filter) { - store.dispatch(UpdateFilterAction(filter)); - }, - activeFilter: store.state.activeFilter, - ); - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is _ViewModel && - runtimeType == other.runtimeType && - activeFilter == other.activeFilter; - - @override - int get hashCode => activeFilter.hashCode; -} diff --git a/firestore_redux/lib/containers/filtered_todos.dart b/firestore_redux/lib/containers/filtered_todos.dart deleted file mode 100644 index 1c72ed78..00000000 --- a/firestore_redux/lib/containers/filtered_todos.dart +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/presentation/todo_list.dart'; -import 'package:fire_redux_sample/selectors/selectors.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -class FilteredTodos extends StatelessWidget { - FilteredTodos({Key key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return StoreConnector( - converter: _ViewModel.fromStore, - builder: (context, vm) { - return TodoList( - todos: vm.todos, - onCheckboxChanged: vm.onCheckboxChanged, - onRemove: vm.onRemove, - onUndoRemove: vm.onUndoRemove, - ); - }, - ); - } -} - -class _ViewModel { - final List todos; - final bool loading; - final Function(Todo, bool) onCheckboxChanged; - final Function(Todo) onRemove; - final Function(Todo) onUndoRemove; - - _ViewModel({ - @required this.todos, - @required this.loading, - @required this.onCheckboxChanged, - @required this.onRemove, - @required this.onUndoRemove, - }); - - static _ViewModel fromStore(Store store) { - return _ViewModel( - todos: filteredTodosSelector( - todosSelector(store.state), - activeFilterSelector(store.state), - ), - loading: store.state.isLoading, - onCheckboxChanged: (todo, complete) { - store.dispatch(UpdateTodoAction( - todo.id, - todo.copyWith(complete: !todo.complete), - )); - }, - onRemove: (todo) { - store.dispatch(DeleteTodoAction(todo.id)); - }, - onUndoRemove: (todo) { - store.dispatch(AddTodoAction(todo)); - }, - ); - } -} diff --git a/firestore_redux/lib/containers/stats.dart b/firestore_redux/lib/containers/stats.dart deleted file mode 100644 index 3e1f73c4..00000000 --- a/firestore_redux/lib/containers/stats.dart +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/presentation/stats_counter.dart'; -import 'package:fire_redux_sample/selectors/selectors.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -class Stats extends StatelessWidget { - Stats({Key key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return StoreConnector( - converter: _ViewModel.fromStore, - builder: (context, vm) { - return StatsCounter( - numActive: vm.numActive, - numCompleted: vm.numCompleted, - ); - }, - ); - } -} - -class _ViewModel { - final int numCompleted; - final int numActive; - - _ViewModel({@required this.numCompleted, @required this.numActive}); - - static _ViewModel fromStore(Store store) { - return _ViewModel( - numActive: numActiveSelector(todosSelector(store.state)), - numCompleted: numCompletedSelector(todosSelector(store.state)), - ); - } -} diff --git a/firestore_redux/lib/containers/tab_selector.dart b/firestore_redux/lib/containers/tab_selector.dart deleted file mode 100644 index c6bd25a2..00000000 --- a/firestore_redux/lib/containers/tab_selector.dart +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -class TabSelector extends StatelessWidget { - TabSelector({Key key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return StoreConnector( - distinct: true, - converter: _ViewModel.fromStore, - builder: (context, vm) { - return BottomNavigationBar( - key: ArchSampleKeys.tabs, - currentIndex: AppTab.values.indexOf(vm.activeTab), - onTap: vm.onTabSelected, - items: AppTab.values.map((tab) { - return BottomNavigationBarItem( - icon: Icon( - tab == AppTab.todos ? Icons.list : Icons.show_chart, - key: tab == AppTab.todos - ? ArchSampleKeys.todoTab - : ArchSampleKeys.statsTab, - ), - title: Text(tab == AppTab.stats - ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos), - ); - }).toList(), - ); - }, - ); - } -} - -class _ViewModel { - final AppTab activeTab; - final Function(int) onTabSelected; - - _ViewModel({ - @required this.activeTab, - @required this.onTabSelected, - }); - - static _ViewModel fromStore(Store store) { - return _ViewModel( - activeTab: store.state.activeTab, - onTabSelected: (index) { - store.dispatch(UpdateTabAction((AppTab.values[index]))); - }, - ); - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is _ViewModel && - runtimeType == other.runtimeType && - activeTab == other.activeTab; - - @override - int get hashCode => activeTab.hashCode; -} diff --git a/firestore_redux/lib/containers/todo_details.dart b/firestore_redux/lib/containers/todo_details.dart deleted file mode 100644 index 6f7ad5a6..00000000 --- a/firestore_redux/lib/containers/todo_details.dart +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/presentation/details_screen.dart'; -import 'package:fire_redux_sample/selectors/selectors.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -class TodoDetails extends StatelessWidget { - final String id; - - TodoDetails({Key key, @required this.id}) : super(key: key); - - @override - Widget build(BuildContext context) { - return StoreConnector( - ignoreChange: (state) => todoSelector(state.todos, id).isNotPresent, - converter: (Store store) { - return _ViewModel.from(store, id); - }, - builder: (context, vm) { - return DetailsScreen( - todo: vm.todo, - onDelete: vm.onDelete, - toggleCompleted: vm.toggleCompleted, - ); - }, - ); - } -} - -class _ViewModel { - final Todo todo; - final Function onDelete; - final Function(bool) toggleCompleted; - - _ViewModel({ - @required this.todo, - @required this.onDelete, - @required this.toggleCompleted, - }); - - factory _ViewModel.from(Store store, String id) { - final todo = todoSelector(todosSelector(store.state), id).value; - - return _ViewModel( - todo: todo, - onDelete: () => store.dispatch(DeleteTodoAction(todo.id)), - toggleCompleted: (isComplete) { - store.dispatch(UpdateTodoAction( - todo.id, - todo.copyWith(complete: isComplete), - )); - }, - ); - } -} diff --git a/firestore_redux/lib/localization.dart b/firestore_redux/lib/localization.dart deleted file mode 100644 index c2715fb6..00000000 --- a/firestore_redux/lib/localization.dart +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter/material.dart'; - -class FirestoreReduxLocalizations { - static FirestoreReduxLocalizations of(BuildContext context) { - return Localizations.of( - context, - FirestoreReduxLocalizations, - ); - } - - String get appTitle => 'Firestore Redux Example'; -} - -class FirestoreReduxLocalizationsDelegate - extends LocalizationsDelegate { - @override - Future load(Locale locale) => - Future(() => FirestoreReduxLocalizations()); - - @override - bool shouldReload(FirestoreReduxLocalizationsDelegate old) => false; - - @override - bool isSupported(Locale locale) => - locale.languageCode.toLowerCase().contains('en'); -} diff --git a/firestore_redux/lib/main.dart b/firestore_redux/lib/main.dart deleted file mode 100644 index 2482ffbe..00000000 --- a/firestore_redux/lib/main.dart +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/containers/add_todo.dart'; -import 'package:fire_redux_sample/localization.dart'; -import 'package:fire_redux_sample/middleware/store_todos_middleware.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/presentation/home_screen.dart'; -import 'package:fire_redux_sample/reducers/app_state_reducer.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:firebase_flutter_repository/reactive_todos_repository.dart'; -import 'package:firebase_flutter_repository/user_repository.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -void main() { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(ReduxApp()); -} - -class ReduxApp extends StatelessWidget { - final Store store; - - ReduxApp({ - Key key, - ReactiveTodosRepository todosRepository, - UserRepository userRepository, - }) : store = Store( - appReducer, - initialState: AppState.loading(), - middleware: createStoreTodosMiddleware( - todosRepository ?? - FirestoreReactiveTodosRepository(Firestore.instance), - userRepository ?? FirebaseUserRepository(FirebaseAuth.instance), - ), - ), - super(key: key) { - store.dispatch(InitAppAction()); - } - - @override - Widget build(BuildContext context) { - return StoreProvider( - store: store, - child: MaterialApp( - onGenerateTitle: (context) => - FirestoreReduxLocalizations.of(context).appTitle, - theme: ArchSampleTheme.theme, - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - FirestoreReduxLocalizationsDelegate(), - ], - routes: { - ArchSampleRoutes.home: (context) => HomeScreen(), - ArchSampleRoutes.addTodo: (context) => AddTodo(), - }, - ), - ); - } -} diff --git a/firestore_redux/lib/middleware/store_todos_middleware.dart b/firestore_redux/lib/middleware/store_todos_middleware.dart deleted file mode 100644 index 01f95629..00000000 --- a/firestore_redux/lib/middleware/store_todos_middleware.dart +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/selectors/selectors.dart'; -import 'package:redux/redux.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -List> createStoreTodosMiddleware( - ReactiveTodosRepository todosRepository, - UserRepository userRepository, -) { - return [ - TypedMiddleware( - _firestoreSignIn(userRepository), - ), - TypedMiddleware( - _firestoreConnect(todosRepository), - ), - TypedMiddleware( - _firestoreSaveNewTodo(todosRepository), - ), - TypedMiddleware( - _firestoreDeleteTodo(todosRepository), - ), - TypedMiddleware( - _firestoreUpdateTodo(todosRepository), - ), - TypedMiddleware( - _firestoreToggleAll(todosRepository), - ), - TypedMiddleware( - _firestoreClearCompleted(todosRepository), - ), - ]; -} - -void Function( - Store store, - InitAppAction action, - NextDispatcher next, -) _firestoreSignIn( - UserRepository repository, -) { - return (store, action, next) { - next(action); - - repository.login().then((_) { - store.dispatch(ConnectToDataSourceAction()); - }); - }; -} - -void Function( - Store store, - ConnectToDataSourceAction action, - NextDispatcher next, -) _firestoreConnect( - ReactiveTodosRepository repository, -) { - return (store, action, next) { - next(action); - - repository.todos().listen((todos) { - store.dispatch(LoadTodosAction(todos.map(Todo.fromEntity).toList())); - }); - }; -} - -void Function( - Store store, - AddTodoAction action, - NextDispatcher next, -) _firestoreSaveNewTodo( - ReactiveTodosRepository repository, -) { - return (store, action, next) { - next(action); - repository.addNewTodo(action.todo.toEntity()); - }; -} - -void Function( - Store store, - DeleteTodoAction action, - NextDispatcher next, -) _firestoreDeleteTodo( - ReactiveTodosRepository repository, -) { - return (store, action, next) { - next(action); - repository.deleteTodo([action.id]); - }; -} - -void Function( - Store store, - UpdateTodoAction action, - NextDispatcher next, -) _firestoreUpdateTodo( - ReactiveTodosRepository repository, -) { - return (store, action, next) { - next(action); - repository.updateTodo(action.updatedTodo.toEntity()); - }; -} - -void Function( - Store store, - ToggleAllAction action, - NextDispatcher next, -) _firestoreToggleAll( - ReactiveTodosRepository repository, -) { - return (store, action, next) { - next(action); - var todos = todosSelector(store.state); - - for (var todo in todos) { - if (allCompleteSelector(todos)) { - if (todo.complete) { - repository.updateTodo(todo.copyWith(complete: false).toEntity()); - } - } else { - if (!todo.complete) { - repository.updateTodo(todo.copyWith(complete: true).toEntity()); - } - } - } - }; -} - -void Function( - Store store, - ClearCompletedAction action, - NextDispatcher next, -) _firestoreClearCompleted( - ReactiveTodosRepository repository, -) { - return (store, action, next) { - next(action); - - repository.deleteTodo( - completeTodosSelector(todosSelector(store.state)) - .map((todo) => todo.id) - .toList(), - ); - }; -} diff --git a/firestore_redux/lib/models/app_state.dart b/firestore_redux/lib/models/app_state.dart deleted file mode 100644 index b53a31dc..00000000 --- a/firestore_redux/lib/models/app_state.dart +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; -import 'package:meta/meta.dart'; - -@immutable -class AppState { - final bool isLoading; - final List todos; - final AppTab activeTab; - final VisibilityFilter activeFilter; - - AppState({ - this.isLoading = false, - this.todos = const [], - this.activeTab = AppTab.todos, - this.activeFilter = VisibilityFilter.all, - }); - - factory AppState.loading() => AppState(isLoading: true); - - AppState copyWith({ - bool isLoading, - List todos, - AppTab activeTab, - VisibilityFilter activeFilter, - }) { - return AppState( - isLoading: isLoading ?? this.isLoading, - todos: todos ?? this.todos, - activeTab: activeTab ?? this.activeTab, - activeFilter: activeFilter ?? this.activeFilter, - ); - } - - @override - int get hashCode => - isLoading.hashCode ^ - todos.hashCode ^ - activeTab.hashCode ^ - activeFilter.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is AppState && - runtimeType == other.runtimeType && - isLoading == other.isLoading && - todos == other.todos && - activeTab == other.activeTab && - activeFilter == other.activeFilter; - - @override - String toString() { - return 'AppState{isLoading: $isLoading, todos: $todos, activeTab: $activeTab, activeFilter: $activeFilter}'; - } -} diff --git a/firestore_redux/lib/models/app_tab.dart b/firestore_redux/lib/models/app_tab.dart deleted file mode 100644 index 096b6f56..00000000 --- a/firestore_redux/lib/models/app_tab.dart +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -enum AppTab { todos, stats } diff --git a/firestore_redux/lib/models/extra_action.dart b/firestore_redux/lib/models/extra_action.dart deleted file mode 100644 index 236a7d0b..00000000 --- a/firestore_redux/lib/models/extra_action.dart +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -enum ExtraAction { toggleAllComplete, clearCompleted } diff --git a/firestore_redux/lib/models/models.dart b/firestore_redux/lib/models/models.dart deleted file mode 100644 index 6951f5b7..00000000 --- a/firestore_redux/lib/models/models.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -export 'app_state.dart'; -export 'app_tab.dart'; -export 'extra_action.dart'; -export 'todo.dart'; -export 'visibility_filter.dart'; diff --git a/firestore_redux/lib/models/todo.dart b/firestore_redux/lib/models/todo.dart deleted file mode 100644 index 25ca0bd6..00000000 --- a/firestore_redux/lib/models/todo.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:meta/meta.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -@immutable -class Todo { - final bool complete; - final String id; - final String note; - final String task; - - Todo(this.task, {this.complete = false, String note = '', String id}) - : note = note ?? '', - id = id ?? Uuid().generateV4(); - - Todo copyWith({bool complete, String id, String note, String task}) { - return Todo( - task ?? this.task, - complete: complete ?? this.complete, - id: id ?? this.id, - note: note ?? this.note, - ); - } - - @override - int get hashCode => - complete.hashCode ^ task.hashCode ^ note.hashCode ^ id.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is Todo && - runtimeType == other.runtimeType && - complete == other.complete && - task == other.task && - note == other.note && - id == other.id; - - @override - String toString() { - return 'Todo{complete: $complete, task: $task, note: $note, id: $id}'; - } - - TodoEntity toEntity() { - return TodoEntity(task, id, note, complete); - } - - static Todo fromEntity(TodoEntity entity) { - return Todo( - entity.task, - complete: entity.complete ?? false, - note: entity.note, - id: entity.id ?? Uuid().generateV4(), - ); - } -} diff --git a/firestore_redux/lib/models/visibility_filter.dart b/firestore_redux/lib/models/visibility_filter.dart deleted file mode 100644 index 11f11982..00000000 --- a/firestore_redux/lib/models/visibility_filter.dart +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -enum VisibilityFilter { all, active, completed } diff --git a/firestore_redux/lib/presentation/add_edit_screen.dart b/firestore_redux/lib/presentation/add_edit_screen.dart deleted file mode 100644 index fa15f4b7..00000000 --- a/firestore_redux/lib/presentation/add_edit_screen.dart +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -typedef OnSaveCallback = void Function(String task, String note); - -class AddEditScreen extends StatefulWidget { - final bool isEditing; - final OnSaveCallback onSave; - final Todo todo; - - AddEditScreen( - {Key key, @required this.onSave, @required this.isEditing, this.todo}) - : super(key: key ?? ArchSampleKeys.addTodoScreen); - @override - _AddEditScreenState createState() => _AddEditScreenState(); -} - -class _AddEditScreenState extends State { - static final GlobalKey _formKey = GlobalKey(); - - String _task; - String _note; - - bool get isEditing => widget.isEditing; - - @override - Widget build(BuildContext context) { - final localizations = ArchSampleLocalizations.of(context); - final textTheme = Theme.of(context).textTheme; - - return Scaffold( - appBar: AppBar( - title: Text( - isEditing ? localizations.editTodo : localizations.addTodo, - ), - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: Form( - key: _formKey, - child: ListView( - children: [ - TextFormField( - initialValue: isEditing ? widget.todo.task : '', - key: ArchSampleKeys.taskField, - autofocus: !isEditing, - style: textTheme.headline, - decoration: InputDecoration( - hintText: localizations.newTodoHint, - ), - validator: (val) { - return val.trim().isEmpty - ? localizations.emptyTodoError - : null; - }, - onSaved: (value) => _task = value, - ), - TextFormField( - initialValue: isEditing ? widget.todo.note : '', - key: ArchSampleKeys.noteField, - maxLines: 10, - style: textTheme.subhead, - decoration: InputDecoration( - hintText: localizations.notesHint, - ), - onSaved: (value) => _note = value, - ) - ], - ), - ), - ), - floatingActionButton: FloatingActionButton( - key: - isEditing ? ArchSampleKeys.saveTodoFab : ArchSampleKeys.saveNewTodo, - tooltip: isEditing ? localizations.saveChanges : localizations.addTodo, - child: Icon(isEditing ? Icons.check : Icons.add), - onPressed: () { - if (_formKey.currentState.validate()) { - _formKey.currentState.save(); - widget.onSave(_task, _note); - - Navigator.pop(context); - } - }, - ), - ); - } -} diff --git a/firestore_redux/lib/presentation/details_screen.dart b/firestore_redux/lib/presentation/details_screen.dart deleted file mode 100644 index af689d83..00000000 --- a/firestore_redux/lib/presentation/details_screen.dart +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/containers/edit_todo.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class DetailsScreen extends StatelessWidget { - final Todo todo; - final Function onDelete; - final Function(bool) toggleCompleted; - - DetailsScreen({ - Key key, - @required this.todo, - @required this.onDelete, - @required this.toggleCompleted, - }) : super(key: key ?? ArchSampleKeys.todoDetailsScreen); - - @override - Widget build(BuildContext context) { - final localizations = ArchSampleLocalizations.of(context); - - return Scaffold( - appBar: AppBar( - title: Text(localizations.todoDetails), - actions: [ - IconButton( - tooltip: localizations.deleteTodo, - key: ArchSampleKeys.deleteTodoButton, - icon: Icon(Icons.delete), - onPressed: () { - onDelete(); - Navigator.pop(context, todo); - }, - ) - ], - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: ListView( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(right: 8.0), - child: Checkbox( - value: todo.complete, - onChanged: toggleCompleted, - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Hero( - tag: '${todo.id}__heroTag', - child: Container( - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), - child: Text( - todo.task, - key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, - ), - ), - ), - Text( - todo.note, - key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ), - ], - ), - ), - ], - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - key: ArchSampleKeys.editTodoFab, - tooltip: localizations.editTodo, - child: Icon(Icons.edit), - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) { - return EditTodo( - todo: todo, - ); - }, - ), - ); - }, - ), - ); - } -} diff --git a/firestore_redux/lib/presentation/extra_actions_button.dart b/firestore_redux/lib/presentation/extra_actions_button.dart deleted file mode 100644 index 0a629ee9..00000000 --- a/firestore_redux/lib/presentation/extra_actions_button.dart +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class ExtraActionsButton extends StatelessWidget { - final PopupMenuItemSelected onSelected; - final bool allComplete; - - ExtraActionsButton({ - this.onSelected, - this.allComplete = false, - Key key, - }) : super(key: ArchSampleKeys.extraActionsButton); - - @override - Widget build(BuildContext context) { - return PopupMenuButton( - onSelected: onSelected, - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - key: ArchSampleKeys.toggleAll, - value: ExtraAction.toggleAllComplete, - child: Text(allComplete - ? ArchSampleLocalizations.of(context).markAllIncomplete - : ArchSampleLocalizations.of(context).markAllComplete), - ), - PopupMenuItem( - key: ArchSampleKeys.clearCompleted, - value: ExtraAction.clearCompleted, - child: Text(ArchSampleLocalizations.of(context).clearCompleted), - ), - ], - ); - } -} diff --git a/firestore_redux/lib/presentation/filter_button.dart b/firestore_redux/lib/presentation/filter_button.dart deleted file mode 100644 index bee83068..00000000 --- a/firestore_redux/lib/presentation/filter_button.dart +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class FilterButton extends StatelessWidget { - final PopupMenuItemSelected onSelected; - final VisibilityFilter activeFilter; - final bool visible; - - FilterButton({this.onSelected, this.activeFilter, this.visible, Key key}) - : super(key: key); - - @override - Widget build(BuildContext context) { - final defaultStyle = Theme.of(context).textTheme.body1; - final activeStyle = Theme.of(context) - .textTheme - .body1 - .copyWith(color: Theme.of(context).accentColor); - final button = _Button( - onSelected: onSelected, - activeFilter: activeFilter, - activeStyle: activeStyle, - defaultStyle: defaultStyle, - ); - - return AnimatedOpacity( - opacity: visible ? 1.0 : 0.0, - duration: Duration(milliseconds: 150), - child: visible ? button : IgnorePointer(child: button), - ); - } -} - -class _Button extends StatelessWidget { - const _Button({ - Key key, - @required this.onSelected, - @required this.activeFilter, - @required this.activeStyle, - @required this.defaultStyle, - }) : super(key: key); - - final PopupMenuItemSelected onSelected; - final VisibilityFilter activeFilter; - final TextStyle activeStyle; - final TextStyle defaultStyle; - - @override - Widget build(BuildContext context) { - return PopupMenuButton( - key: ArchSampleKeys.filterButton, - tooltip: ArchSampleLocalizations.of(context).filterTodos, - onSelected: onSelected, - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - key: ArchSampleKeys.allFilter, - value: VisibilityFilter.all, - child: Text( - ArchSampleLocalizations.of(context).showAll, - style: activeFilter == VisibilityFilter.all - ? activeStyle - : defaultStyle, - ), - ), - PopupMenuItem( - key: ArchSampleKeys.activeFilter, - value: VisibilityFilter.active, - child: Text( - ArchSampleLocalizations.of(context).showActive, - style: activeFilter == VisibilityFilter.active - ? activeStyle - : defaultStyle, - ), - ), - PopupMenuItem( - key: ArchSampleKeys.completedFilter, - value: VisibilityFilter.completed, - child: Text( - ArchSampleLocalizations.of(context).showCompleted, - style: activeFilter == VisibilityFilter.completed - ? activeStyle - : defaultStyle, - ), - ), - ], - icon: Icon(Icons.filter_list), - ); - } -} diff --git a/firestore_redux/lib/presentation/home_screen.dart b/firestore_redux/lib/presentation/home_screen.dart deleted file mode 100644 index 80f9a777..00000000 --- a/firestore_redux/lib/presentation/home_screen.dart +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/containers/active_tab.dart'; -import 'package:fire_redux_sample/containers/extra_actions_container.dart'; -import 'package:fire_redux_sample/containers/filter_selector.dart'; -import 'package:fire_redux_sample/containers/filtered_todos.dart'; -import 'package:fire_redux_sample/containers/stats.dart'; -import 'package:fire_redux_sample/containers/tab_selector.dart'; -import 'package:fire_redux_sample/localization.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class HomeScreen extends StatelessWidget { - HomeScreen() : super(key: ArchSampleKeys.homeScreen); - - @override - Widget build(BuildContext context) { - return ActiveTab( - builder: (BuildContext context, AppTab activeTab) { - return Scaffold( - appBar: AppBar( - title: Text(FirestoreReduxLocalizations.of(context).appTitle), - actions: [ - FilterSelector(visible: activeTab == AppTab.todos), - ExtraActionsContainer(), - ], - ), - body: activeTab == AppTab.todos ? FilteredTodos() : Stats(), - floatingActionButton: FloatingActionButton( - key: ArchSampleKeys.addTodoFab, - onPressed: () { - Navigator.pushNamed(context, ArchSampleRoutes.addTodo); - }, - child: Icon(Icons.add), - tooltip: ArchSampleLocalizations.of(context).addTodo, - ), - bottomNavigationBar: TabSelector(), - ); - }, - ); - } -} diff --git a/firestore_redux/lib/presentation/loading_indicator.dart b/firestore_redux/lib/presentation/loading_indicator.dart deleted file mode 100644 index 822a4c32..00000000 --- a/firestore_redux/lib/presentation/loading_indicator.dart +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/material.dart'; - -class LoadingIndicator extends StatelessWidget { - LoadingIndicator({Key key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Center( - child: CircularProgressIndicator(), - ); - } -} diff --git a/firestore_redux/lib/presentation/stats_counter.dart b/firestore_redux/lib/presentation/stats_counter.dart deleted file mode 100644 index 95346166..00000000 --- a/firestore_redux/lib/presentation/stats_counter.dart +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/containers/app_loading.dart'; -import 'package:fire_redux_sample/presentation/loading_indicator.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class StatsCounter extends StatelessWidget { - final int numActive; - final int numCompleted; - - StatsCounter({ - @required this.numActive, - @required this.numCompleted, - }); - - @override - Widget build(BuildContext context) { - return AppLoading(builder: (context, loading) { - return loading - ? LoadingIndicator(key: Key('__statsLoading__')) - : _buildStats(context); - }); - } - - Widget _buildStats(BuildContext context) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '$numCompleted', - key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '$numActive', - key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, - ), - ) - ], - ), - ); - } -} diff --git a/firestore_redux/lib/presentation/todo_item.dart b/firestore_redux/lib/presentation/todo_item.dart deleted file mode 100644 index c46b271b..00000000 --- a/firestore_redux/lib/presentation/todo_item.dart +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class TodoItem extends StatelessWidget { - final DismissDirectionCallback onDismissed; - final GestureTapCallback onTap; - final ValueChanged onCheckboxChanged; - final Todo todo; - - TodoItem({ - @required this.onDismissed, - @required this.onTap, - @required this.onCheckboxChanged, - @required this.todo, - }); - - @override - Widget build(BuildContext context) { - return Dismissible( - key: ArchSampleKeys.todoItem(todo.id), - onDismissed: onDismissed, - child: ListTile( - onTap: onTap, - leading: Checkbox( - key: ArchSampleKeys.todoItemCheckbox(todo.id), - value: todo.complete, - onChanged: onCheckboxChanged, - ), - title: Hero( - tag: '${todo.id}__heroTag', - child: Container( - width: MediaQuery.of(context).size.width, - child: Text( - todo.task, - key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, - ), - ), - ), - subtitle: Text( - todo.note, - key: ArchSampleKeys.todoItemNote(todo.id), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, - ), - ), - ); - } -} diff --git a/firestore_redux/lib/presentation/todo_list.dart b/firestore_redux/lib/presentation/todo_list.dart deleted file mode 100644 index 9d9990a7..00000000 --- a/firestore_redux/lib/presentation/todo_list.dart +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/containers/app_loading.dart'; -import 'package:fire_redux_sample/containers/todo_details.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/presentation/loading_indicator.dart'; -import 'package:fire_redux_sample/presentation/todo_item.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class TodoList extends StatelessWidget { - final List todos; - final Function(Todo, bool) onCheckboxChanged; - final Function(Todo) onRemove; - final Function(Todo) onUndoRemove; - - TodoList({ - Key key, - @required this.todos, - @required this.onCheckboxChanged, - @required this.onRemove, - @required this.onUndoRemove, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return AppLoading(builder: (context, loading) { - return loading - ? LoadingIndicator(key: ArchSampleKeys.todosLoading) - : _buildListView(); - }); - } - - ListView _buildListView() { - return ListView.builder( - key: ArchSampleKeys.todoList, - itemCount: todos.length, - itemBuilder: (BuildContext context, int index) { - final todo = todos[index]; - - return TodoItem( - todo: todo, - onDismissed: (direction) { - _removeTodo(context, todo); - }, - onTap: () => _onTodoTap(context, todo), - onCheckboxChanged: (complete) { - onCheckboxChanged(todo, complete); - }, - ); - }, - ); - } - - void _removeTodo(BuildContext context, Todo todo) { - onRemove(todo); - - Scaffold.of(context).showSnackBar(SnackBar( - duration: Duration(seconds: 2), - content: Text( - ArchSampleLocalizations.of(context).todoDeleted(todo.task), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - action: SnackBarAction( - label: ArchSampleLocalizations.of(context).undo, - onPressed: () => onUndoRemove(todo), - ))); - } - - void _onTodoTap(BuildContext context, Todo todo) { - Navigator.of(context) - .push(MaterialPageRoute( - builder: (_) => TodoDetails(id: todo.id), - )) - .then((removedTodo) { - if (removedTodo != null) { - Scaffold.of(context).showSnackBar(SnackBar( - key: ArchSampleKeys.snackbar, - duration: Duration(seconds: 2), - content: Text( - ArchSampleLocalizations.of(context).todoDeleted(todo.task), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - action: SnackBarAction( - label: ArchSampleLocalizations.of(context).undo, - onPressed: () { - onUndoRemove(todo); - }, - ))); - } - }); - } -} diff --git a/firestore_redux/lib/presentation/typedefs.dart b/firestore_redux/lib/presentation/typedefs.dart deleted file mode 100644 index 1ac56175..00000000 --- a/firestore_redux/lib/presentation/typedefs.dart +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; - -typedef TodoAdder = void Function(Todo todo); - -typedef TodoRemover = void Function(String id); - -typedef TodoUpdater = void Function(String id, Todo todo); diff --git a/firestore_redux/lib/reducers/app_state_reducer.dart b/firestore_redux/lib/reducers/app_state_reducer.dart deleted file mode 100644 index 883a49c9..00000000 --- a/firestore_redux/lib/reducers/app_state_reducer.dart +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/reducers/loading_reducer.dart'; -import 'package:fire_redux_sample/reducers/tabs_reducer.dart'; -import 'package:fire_redux_sample/reducers/todos_reducer.dart'; -import 'package:fire_redux_sample/reducers/visibility_reducer.dart'; - -// We create the State reducer by combining many smaller reducers into one! -AppState appReducer(AppState state, action) { - return AppState( - isLoading: loadingReducer(state.isLoading, action), - todos: todosReducer(state.todos, action), - activeFilter: visibilityReducer(state.activeFilter, action), - activeTab: tabsReducer(state.activeTab, action), - ); -} diff --git a/firestore_redux/lib/reducers/loading_reducer.dart b/firestore_redux/lib/reducers/loading_reducer.dart deleted file mode 100644 index b97aa3a4..00000000 --- a/firestore_redux/lib/reducers/loading_reducer.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:redux/redux.dart'; - -final loadingReducer = combineReducers([ - TypedReducer(_setLoaded), -]); - -bool _setLoaded(bool state, action) { - return false; -} diff --git a/firestore_redux/lib/reducers/tabs_reducer.dart b/firestore_redux/lib/reducers/tabs_reducer.dart deleted file mode 100644 index b6c2cb22..00000000 --- a/firestore_redux/lib/reducers/tabs_reducer.dart +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:redux/redux.dart'; - -final tabsReducer = combineReducers([ - TypedReducer(_activeTabReducer), -]); - -AppTab _activeTabReducer(AppTab activeTab, UpdateTabAction action) { - return action.newTab; -} diff --git a/firestore_redux/lib/reducers/todos_reducer.dart b/firestore_redux/lib/reducers/todos_reducer.dart deleted file mode 100644 index 8994afa0..00000000 --- a/firestore_redux/lib/reducers/todos_reducer.dart +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:redux/redux.dart'; - -final todosReducer = combineReducers>([ - TypedReducer, LoadTodosAction>(_setLoadedTodos), - TypedReducer, DeleteTodoAction>(_deleteTodo), -]); - -List _setLoadedTodos(List todos, LoadTodosAction action) { - return action.todos; -} - -List _deleteTodo(List todos, DeleteTodoAction action) { - return todos..removeWhere((todo) => todo.id == action.id); -} diff --git a/firestore_redux/lib/reducers/visibility_reducer.dart b/firestore_redux/lib/reducers/visibility_reducer.dart deleted file mode 100644 index 2df66d19..00000000 --- a/firestore_redux/lib/reducers/visibility_reducer.dart +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:redux/redux.dart'; - -final visibilityReducer = combineReducers([ - TypedReducer(_activeFilterReducer), -]); - -VisibilityFilter _activeFilterReducer( - VisibilityFilter activeFilter, UpdateFilterAction action) { - return action.newFilter; -} diff --git a/firestore_redux/lib/selectors/selectors.dart b/firestore_redux/lib/selectors/selectors.dart deleted file mode 100644 index 989172e0..00000000 --- a/firestore_redux/lib/selectors/selectors.dart +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -List todosSelector(AppState state) => state.todos; - -VisibilityFilter activeFilterSelector(AppState state) => state.activeFilter; - -AppTab activeTabSelector(AppState state) => state.activeTab; - -bool isLoadingSelector(AppState state) => state.isLoading; - -bool allCompleteSelector(List todos) => - todos.every((todo) => todo.complete); - -int numActiveSelector(List todos) => activeTodosSelector(todos).length; - -int numCompletedSelector(List todos) => - completeTodosSelector(todos).length; - -List activeTodosSelector(List todos) => - todos.where((todo) => !todo.complete).toList(); - -List completeTodosSelector(List todos) => - todos.where((todo) => todo.complete).toList(); - -List filteredTodosSelector( - List todos, - VisibilityFilter activeFilter, -) { - switch (activeFilter) { - case VisibilityFilter.active: - return activeTodosSelector(todos); - case VisibilityFilter.completed: - return completeTodosSelector(todos); - case VisibilityFilter.all: - default: - return todos; - } -} - -Optional todoSelector(List todos, String id) { - try { - return Optional.of(todos.firstWhere((todo) => todo.id == id)); - } catch (e) { - return Optional.absent(); - } -} diff --git a/firestore_redux/pubspec.yaml b/firestore_redux/pubspec.yaml deleted file mode 100644 index 6d15d4fb..00000000 --- a/firestore_redux/pubspec.yaml +++ /dev/null @@ -1,82 +0,0 @@ -name: fire_redux_sample -description: A new Flutter project. - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 - -environment: - sdk: ">=2.1.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - meta: '>=1.1.0 <2.0.0' - redux: ^4.0.0 - flutter_redux: ^0.6.0 - todos_app_core: - path: ../todos_app_core - firebase_flutter_repository: - path: ../firebase_flutter_repository - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_driver: - sdk: flutter - test: - mockito: - integration_tests: - path: ../integration_tests - todos_repository_local_storage: - path: ../todos_repository_local_storage - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/firestore_redux/test/all_tests.dart b/firestore_redux/test/all_tests.dart deleted file mode 100644 index 53c95150..00000000 --- a/firestore_redux/test/all_tests.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'middleware_test.dart' as middleware; -import 'reducer_test.dart' as reducer; -import 'selectors_test.dart' as selector; - -void main() { - middleware.main(); - reducer.main(); - selector.main(); -} diff --git a/firestore_redux/test/middleware_test.dart b/firestore_redux/test/middleware_test.dart deleted file mode 100644 index f2d37ed8..00000000 --- a/firestore_redux/test/middleware_test.dart +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/middleware/store_todos_middleware.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/reducers/app_state_reducer.dart'; -import 'package:flutter/foundation.dart'; -import 'package:mockito/mockito.dart'; -import 'package:redux/redux.dart'; -import 'package:test/test.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -class MockReactiveTodosRepository extends Mock - implements ReactiveTodosRepository {} - -class MockUserRepository extends Mock implements UserRepository {} - -class MockMiddleware extends Mock implements MiddlewareClass {} - -void main() { - group('Middleware', () { - test('should log in and start listening for changes', () { - final todosRepository = MockReactiveTodosRepository(); - final userRepository = MockUserRepository(); - final captor = MockMiddleware(); - final store = Store( - appReducer, - initialState: AppState.loading(), - middleware: createStoreTodosMiddleware(todosRepository, userRepository) - ..add(captor), - ); - - when(userRepository.login()).thenAnswer((_) => SynchronousFuture(null)); - when(todosRepository.todos()) - .thenAnswer((_) => StreamController>().stream); - - store.dispatch(InitAppAction()); - - verify(userRepository.login()); - verify(todosRepository.todos()); - verify(captor.call( - any, - TypeMatcher(), - any, - ) as dynamic); - }); - - test('should convert entities to todos', () async { - // ignore: close_sinks - final controller = StreamController>(sync: true); - final todo = Todo('A'); - final todosRepository = MockReactiveTodosRepository(); - final userRepository = MockUserRepository(); - final captor = MockMiddleware(); - final store = Store( - appReducer, - initialState: AppState.loading(), - middleware: createStoreTodosMiddleware(todosRepository, userRepository) - ..add(captor), - ); - - when(todosRepository.todos()).thenAnswer((_) => controller.stream); - - store.dispatch(ConnectToDataSourceAction()); - controller.add([todo.toEntity()]); - - verify(captor.call( - any, - TypeMatcher(), - any, - ) as dynamic); - }); - - test('should send todos to the repository', () { - final todo = Todo('T'); - final todosRepository = MockReactiveTodosRepository(); - final userRepository = MockUserRepository(); - final store = Store( - appReducer, - initialState: AppState.loading(), - middleware: createStoreTodosMiddleware(todosRepository, userRepository), - ); - - store.dispatch(AddTodoAction(todo)); - verify(todosRepository.addNewTodo(todo.toEntity())); - }); - - test('should clear the completed todos from the repository', () { - final todoA = Todo('A'); - final todoB = Todo('B', complete: true); - final todoC = Todo('C', complete: true); - final todosRepository = MockReactiveTodosRepository(); - final userRepository = MockUserRepository(); - final store = Store( - appReducer, - initialState: AppState(todos: [ - todoA, - todoB, - todoC, - ]), - middleware: createStoreTodosMiddleware(todosRepository, userRepository), - ); - - store.dispatch(ClearCompletedAction()); - - verify(todosRepository.deleteTodo([todoB.id, todoC.id])); - }); - - test('should inform the repository to toggle all todos active', () { - final todoA = Todo('A', complete: true); - final todoB = Todo('B', complete: true); - final todosRepository = MockReactiveTodosRepository(); - final userRepository = MockUserRepository(); - final store = Store( - appReducer, - initialState: AppState(todos: [ - todoA, - todoB, - ]), - middleware: createStoreTodosMiddleware(todosRepository, userRepository), - ); - - store.dispatch(ToggleAllAction()); - - verify(todosRepository - .updateTodo(todoA.copyWith(complete: false).toEntity())); - verify(todosRepository - .updateTodo(todoB.copyWith(complete: false).toEntity())); - }); - - test('should inform the repository to toggle all todos complete', () { - final todoA = Todo('A'); - final todoB = Todo('B', complete: true); - final todosRepository = MockReactiveTodosRepository(); - final userRepository = MockUserRepository(); - final store = Store( - appReducer, - initialState: AppState(todos: [ - todoA, - todoB, - ]), - middleware: createStoreTodosMiddleware(todosRepository, userRepository), - ); - - store.dispatch(ToggleAllAction()); - - verify(todosRepository - .updateTodo(todoA.copyWith(complete: true).toEntity())); - }); - - test('should update a todo on firestore', () { - final todo = Todo('A'); - final update = todo.copyWith(task: 'B'); - final todosRepository = MockReactiveTodosRepository(); - final userRepository = MockUserRepository(); - final store = Store( - appReducer, - initialState: AppState(todos: [todo]), - middleware: createStoreTodosMiddleware(todosRepository, userRepository), - ); - - store.dispatch(UpdateTodoAction(todo.id, update)); - - verify(todosRepository.updateTodo(update.toEntity())); - }); - - test('should delete a todo on firestore', () { - final todo = Todo('A'); - final todosRepository = MockReactiveTodosRepository(); - final userRepository = MockUserRepository(); - final store = Store( - appReducer, - initialState: AppState(todos: [todo]), - middleware: createStoreTodosMiddleware(todosRepository, userRepository), - ); - - store.dispatch(DeleteTodoAction(todo.id)); - - verify(todosRepository.deleteTodo([todo.id])); - }); - }); -} diff --git a/firestore_redux/test/reducer_test.dart b/firestore_redux/test/reducer_test.dart deleted file mode 100644 index 2fee7a79..00000000 --- a/firestore_redux/test/reducer_test.dart +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/actions/actions.dart'; -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/reducers/app_state_reducer.dart'; -import 'package:fire_redux_sample/selectors/selectors.dart'; -import 'package:redux/redux.dart'; -import 'package:test/test.dart'; - -void main() { - group('State Reducer', () { - test('should load todos into store', () { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final store = Store( - appReducer, - initialState: AppState.loading(), - ); - - expect(todosSelector(store.state), []); - - store.dispatch(LoadTodosAction(todos)); - - expect(todosSelector(store.state), todos); - }); - - test('should update the VisibilityFilter', () { - final store = Store( - appReducer, - initialState: AppState(activeFilter: VisibilityFilter.active), - ); - - store.dispatch(UpdateFilterAction(VisibilityFilter.completed)); - - expect(store.state.activeFilter, VisibilityFilter.completed); - }); - - test('should update the AppTab', () { - final store = Store( - appReducer, - initialState: AppState(activeTab: AppTab.todos), - ); - - store.dispatch(UpdateTabAction(AppTab.stats)); - - expect(store.state.activeTab, AppTab.stats); - }); - }); -} diff --git a/firestore_redux/test/selectors_test.dart b/firestore_redux/test/selectors_test.dart deleted file mode 100644 index 46011cfb..00000000 --- a/firestore_redux/test/selectors_test.dart +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/models/models.dart'; -import 'package:fire_redux_sample/selectors/selectors.dart'; -import 'package:quiver/core.dart'; -import 'package:test/test.dart'; - -void main() { - group('Selectors', () { - test('should list the active todos', () { - final todoA = Todo('a'); - final todoB = Todo('b'); - final todos = [ - todoA, - todoB, - Todo('c', complete: true), - ]; - - expect(activeTodosSelector(todos), [todoA, todoB]); - }); - - test('should calculate the number of active todos', () { - final todos = [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]; - - expect(numActiveSelector(todos), 2); - }); - - test('should list the completed todos', () { - final todo = Todo('c', complete: true); - final todos = [ - Todo('a'), - Todo('b'), - todo, - ]; - - expect(completeTodosSelector(todos), [todo]); - }); - - test('should calculate the number of completed todos', () { - final todos = [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]; - - expect(numCompletedSelector(todos), 1); - }); - - test('should return all todos if the VisibilityFilter is all', () { - final todos = [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]; - - expect(filteredTodosSelector(todos, VisibilityFilter.all), todos); - }); - - test('should return active todos if the VisibilityFilter is active', () { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - - expect(filteredTodosSelector(todos, VisibilityFilter.active), [ - todo1, - todo2, - ]); - }); - - test('should return completed todos if the VisibilityFilter is completed', - () { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - - expect(filteredTodosSelector(todos, VisibilityFilter.completed), [todo3]); - }); - - test('should return an Optional todo based on id', () { - final todo1 = Todo('a', id: '1'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - - expect(todoSelector(todos, '1'), Optional.of(todo1)); - }); - - test('should return an absent Optional if the id is not found', () { - final todo1 = Todo('a', id: '1'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - - expect(todoSelector(todos, '2'), Optional.absent()); - }); - }); -} diff --git a/firestore_redux/test_driver/mock_reactive_repository.dart b/firestore_redux/test_driver/mock_reactive_repository.dart deleted file mode 100644 index 60901d6a..00000000 --- a/firestore_redux/test_driver/mock_reactive_repository.dart +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:todos_repository_core/todos_repository_core.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -class MockUserRepository implements UserRepository { - @override - Future login([ - delayAuth = const Duration(milliseconds: 200), - ]) { - return Future.delayed(delayAuth); - } -} - -class MockReactiveTodosRepository implements ReactiveTodosRepository { - // ignore: close_sinks - final controller = StreamController>(); - List _todos = []; - - @override - Future addNewTodo(TodoEntity newTodo) async { - _todos.add(newTodo); - controller.add(_todos); - } - - @override - Future> deleteTodo(List idList) async { - _todos.removeWhere((todo) => idList.contains(todo.id)); - controller.add(_todos); - - return []; - } - - @override - Stream> todos({webClient = const WebClient()}) async* { - _todos = await webClient.loadTodos(); - - yield _todos; - - await for (var latest in controller.stream) { - yield latest; - } - } - - @override - Future updateTodo(TodoEntity todo) async { - _todos[_todos.indexWhere((t) => t.id == todo.id)] = todo; - - controller.add(_todos); - } -} diff --git a/firestore_redux/test_driver/todo_app.dart b/firestore_redux/test_driver/todo_app.dart deleted file mode 100644 index 03d803ab..00000000 --- a/firestore_redux/test_driver/todo_app.dart +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:fire_redux_sample/main.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_driver/driver_extension.dart'; - -import 'mock_reactive_repository.dart'; - -void main() { - enableFlutterDriverExtension(); - - runApp(ReduxApp( - todosRepository: MockReactiveTodosRepository(), - userRepository: MockUserRepository(), - )); -} diff --git a/firestore_redux/test_driver/todo_app_test.dart b/firestore_redux/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/firestore_redux/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/freezed_provider_value_notifier/.metadata b/freezed_provider_value_notifier/.metadata index 361e1e4c..05a8ab44 100644 --- a/freezed_provider_value_notifier/.metadata +++ b/freezed_provider_value_notifier/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: 18cd7a3601bcffb36fdf2f679f763b5e827c2e8e - channel: beta + revision: "05db9689081f091050f01aed79f04dce0c750154" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: android + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: ios + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: linux + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: macos + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: web + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: windows + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/freezed_provider_value_notifier/analysis_options.yaml b/freezed_provider_value_notifier/analysis_options.yaml new file mode 100644 index 00000000..134f2137 --- /dev/null +++ b/freezed_provider_value_notifier/analysis_options.yaml @@ -0,0 +1,34 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# 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 +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + # The lint rules applied to this project can be customized in the + # 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 + # and their documentation is published at https://dart.dev/lints. + # + # 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 + # 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 + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/freezed_provider_value_notifier/android/.gitignore b/freezed_provider_value_notifier/android/.gitignore index bc2100d8..be3943c9 100644 --- a/freezed_provider_value_notifier/android/.gitignore +++ b/freezed_provider_value_notifier/android/.gitignore @@ -5,3 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/freezed_provider_value_notifier/android/app/build.gradle b/freezed_provider_value_notifier/android/app/build.gradle deleted file mode 100644 index 6b371432..00000000 --- a/freezed_provider_value_notifier/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.freezed_provider_value_notifier" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/freezed_provider_value_notifier/android/app/build.gradle.kts b/freezed_provider_value_notifier/android/app/build.gradle.kts new file mode 100644 index 00000000..2536170a --- /dev/null +++ b/freezed_provider_value_notifier/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.freezed_provider_value_notifier" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.freezed_provider_value_notifier" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/freezed_provider_value_notifier/android/app/src/debug/AndroidManifest.xml b/freezed_provider_value_notifier/android/app/src/debug/AndroidManifest.xml index 32824a13..399f6981 100644 --- a/freezed_provider_value_notifier/android/app/src/debug/AndroidManifest.xml +++ b/freezed_provider_value_notifier/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/freezed_provider_value_notifier/android/app/src/main/AndroidManifest.xml b/freezed_provider_value_notifier/android/app/src/main/AndroidManifest.xml index 499c4f84..a8725d3f 100644 --- a/freezed_provider_value_notifier/android/app/src/main/AndroidManifest.xml +++ b/freezed_provider_value_notifier/android/app/src/main/AndroidManifest.xml @@ -1,17 +1,13 @@ - - + - - @@ -44,4 +31,15 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + diff --git a/freezed_provider_value_notifier/android/app/src/main/kotlin/com/example/freeze_provider_value_notifier/MainActivity.kt b/freezed_provider_value_notifier/android/app/src/main/kotlin/com/example/freeze_provider_value_notifier/MainActivity.kt deleted file mode 100644 index e723a0f1..00000000 --- a/freezed_provider_value_notifier/android/app/src/main/kotlin/com/example/freeze_provider_value_notifier/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.freezed_provider_value_notifier - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/freezed_provider_value_notifier/android/app/src/main/kotlin/com/example/freezed_provider_value_notifier/MainActivity.kt b/freezed_provider_value_notifier/android/app/src/main/kotlin/com/example/freezed_provider_value_notifier/MainActivity.kt new file mode 100644 index 00000000..2254fc11 --- /dev/null +++ b/freezed_provider_value_notifier/android/app/src/main/kotlin/com/example/freezed_provider_value_notifier/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.freezed_provider_value_notifier + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/freezed_provider_value_notifier/android/app/src/main/res/drawable-v21/launch_background.xml b/freezed_provider_value_notifier/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/freezed_provider_value_notifier/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/freezed_provider_value_notifier/android/app/src/main/res/values-night/styles.xml b/freezed_provider_value_notifier/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/freezed_provider_value_notifier/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/freezed_provider_value_notifier/android/app/src/main/res/values/styles.xml b/freezed_provider_value_notifier/android/app/src/main/res/values/styles.xml index 1f83a33f..cb1ef880 100644 --- a/freezed_provider_value_notifier/android/app/src/main/res/values/styles.xml +++ b/freezed_provider_value_notifier/android/app/src/main/res/values/styles.xml @@ -1,18 +1,18 @@ - - - diff --git a/freezed_provider_value_notifier/android/app/src/profile/AndroidManifest.xml b/freezed_provider_value_notifier/android/app/src/profile/AndroidManifest.xml index 32824a13..399f6981 100644 --- a/freezed_provider_value_notifier/android/app/src/profile/AndroidManifest.xml +++ b/freezed_provider_value_notifier/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/freezed_provider_value_notifier/android/build.gradle b/freezed_provider_value_notifier/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/freezed_provider_value_notifier/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/freezed_provider_value_notifier/android/build.gradle.kts b/freezed_provider_value_notifier/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/freezed_provider_value_notifier/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/freezed_provider_value_notifier/android/gradle.properties b/freezed_provider_value_notifier/android/gradle.properties index 38c8d454..f018a618 100644 --- a/freezed_provider_value_notifier/android/gradle.properties +++ b/freezed_provider_value_notifier/android/gradle.properties @@ -1,4 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/freezed_provider_value_notifier/android/gradle/wrapper/gradle-wrapper.properties b/freezed_provider_value_notifier/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..ac3b4792 100644 --- a/freezed_provider_value_notifier/android/gradle/wrapper/gradle-wrapper.properties +++ b/freezed_provider_value_notifier/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/freezed_provider_value_notifier/android/settings.gradle b/freezed_provider_value_notifier/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/freezed_provider_value_notifier/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/freezed_provider_value_notifier/android/settings.gradle.kts b/freezed_provider_value_notifier/android/settings.gradle.kts new file mode 100644 index 00000000..fb605bc8 --- /dev/null +++ b/freezed_provider_value_notifier/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/freezed_provider_value_notifier/integration_test/app_test.dart b/freezed_provider_value_notifier/integration_test/app_test.dart new file mode 100644 index 00000000..5710df3e --- /dev/null +++ b/freezed_provider_value_notifier/integration_test/app_test.dart @@ -0,0 +1,19 @@ +import 'package:freezed_provider_value_notifier/app.dart'; +import 'package:integration_tests/integration_tests.dart' as integration_tests; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; + +void main() { + integration_tests.run( + appBuilder: () async { + return ProviderApp( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'freezed_provider_value_notifier_test_${DateTime.now().toIso8601String()}', + await SharedPreferences.getInstance(), + ), + ), + ); + }, + ); +} diff --git a/freezed_provider_value_notifier/ios/.gitignore b/freezed_provider_value_notifier/ios/.gitignore index e96ef602..7a7f9873 100644 --- a/freezed_provider_value_notifier/ios/.gitignore +++ b/freezed_provider_value_notifier/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/freezed_provider_value_notifier/ios/Flutter/AppFrameworkInfo.plist b/freezed_provider_value_notifier/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f78..1dc6cf76 100644 --- a/freezed_provider_value_notifier/ios/Flutter/AppFrameworkInfo.plist +++ b/freezed_provider_value_notifier/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 13.0 diff --git a/freezed_provider_value_notifier/ios/Flutter/Debug.xcconfig b/freezed_provider_value_notifier/ios/Flutter/Debug.xcconfig index 592ceee8..ec97fc6f 100644 --- a/freezed_provider_value_notifier/ios/Flutter/Debug.xcconfig +++ b/freezed_provider_value_notifier/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/freezed_provider_value_notifier/ios/Flutter/Release.xcconfig b/freezed_provider_value_notifier/ios/Flutter/Release.xcconfig index 592ceee8..c4855bfe 100644 --- a/freezed_provider_value_notifier/ios/Flutter/Release.xcconfig +++ b/freezed_provider_value_notifier/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/freezed_provider_value_notifier/ios/Podfile b/freezed_provider_value_notifier/ios/Podfile new file mode 100644 index 00000000..620e46eb --- /dev/null +++ b/freezed_provider_value_notifier/ios/Podfile @@ -0,0 +1,43 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '13.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/freezed_provider_value_notifier/ios/Runner.xcodeproj/project.pbxproj b/freezed_provider_value_notifier/ios/Runner.xcodeproj/project.pbxproj index 75bd2f03..b9267a28 100644 --- a/freezed_provider_value_notifier/ios/Runner.xcodeproj/project.pbxproj +++ b/freezed_provider_value_notifier/ios/Runner.xcodeproj/project.pbxproj @@ -3,22 +3,29 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -26,8 +33,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -37,14 +42,14 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -57,20 +62,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -84,6 +93,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -91,6 +101,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -102,7 +113,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -111,16 +121,26 @@ path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; @@ -147,9 +167,14 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -170,11 +195,19 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -191,20 +224,23 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -220,6 +256,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -231,6 +275,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -253,9 +305,9 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -285,6 +337,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -293,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -309,18 +362,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.freezeProviderValueNotifier; + PRODUCT_BUNDLE_IDENTIFIER = com.example.freezedProviderValueNotifier; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -328,11 +377,58 @@ }; name = Profile; }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.freezedProviderValueNotifier.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.freezedProviderValueNotifier.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.freezedProviderValueNotifier.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -362,6 +458,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -376,7 +473,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -386,9 +483,9 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -418,6 +515,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -426,11 +524,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -443,18 +542,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.freezeProviderValueNotifier; + PRODUCT_BUNDLE_IDENTIFIER = com.example.freezedProviderValueNotifier; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -470,18 +565,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.freezeProviderValueNotifier; + PRODUCT_BUNDLE_IDENTIFIER = com.example.freezedProviderValueNotifier; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -492,6 +583,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/freezed_provider_value_notifier/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/freezed_provider_value_notifier/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/freezed_provider_value_notifier/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/freezed_provider_value_notifier/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/freezed_provider_value_notifier/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/freezed_provider_value_notifier/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..e3773d42 100644 --- a/freezed_provider_value_notifier/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/freezed_provider_value_notifier/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + + + + + @@ -61,8 +73,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Freezed Provider Value Notifier CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -39,7 +41,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/freezed_provider_value_notifier/ios/RunnerTests/RunnerTests.swift b/freezed_provider_value_notifier/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/freezed_provider_value_notifier/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/freezed_provider_value_notifier/lib/add_todo_screen.dart b/freezed_provider_value_notifier/lib/add_todo_screen.dart index cf887a07..658c1ed4 100644 --- a/freezed_provider_value_notifier/lib/add_todo_screen.dart +++ b/freezed_provider_value_notifier/lib/add_todo_screen.dart @@ -9,10 +9,10 @@ class AddTodoScreen extends StatefulWidget { const AddTodoScreen() : super(key: ArchSampleKeys.addTodoScreen); @override - _AddTodoScreenState createState() => _AddTodoScreenState(); + AddTodoScreenState createState() => AddTodoScreenState(); } -class _AddTodoScreenState extends State { +class AddTodoScreenState extends State { final _formKey = GlobalKey(); final _titleEditingController = TextEditingController(); final _notesEditingController = TextEditingController(); @@ -30,12 +30,11 @@ class _AddTodoScreenState extends State { final textTheme = Theme.of(context).textTheme; return Scaffold( - appBar: AppBar( - title: Text(localizations.addTodo), - ), + appBar: AppBar(title: Text(localizations.addTodo)), body: Form( key: _formKey, - autovalidate: false, + autovalidateMode: AutovalidateMode.always, + canPop: true, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -46,10 +45,10 @@ class _AddTodoScreenState extends State { decoration: InputDecoration( hintText: localizations.newTodoHint, ), - style: textTheme.headline, + style: textTheme.titleLarge, autofocus: true, validator: (val) { - return val.trim().isEmpty + return val != null && val.trim().isEmpty ? localizations.emptyTodoError : null; }, @@ -57,10 +56,10 @@ class _AddTodoScreenState extends State { TextFormField( key: ArchSampleKeys.noteField, controller: _notesEditingController, - style: textTheme.subhead, + style: textTheme.titleMedium, decoration: InputDecoration(hintText: localizations.notesHint), maxLines: 10, - ) + ), ], ), ), @@ -69,11 +68,13 @@ class _AddTodoScreenState extends State { key: ArchSampleKeys.saveNewTodo, tooltip: localizations.addTodo, onPressed: () { - if (_formKey.currentState.validate()) { - context.read().addTodo(Todo( - _titleEditingController.text, - note: _notesEditingController.text, - )); + if (_formKey.currentState!.validate()) { + context.read().addTodo( + Todo( + _titleEditingController.text, + note: _notesEditingController.text, + ), + ); Navigator.pop(context); } }, diff --git a/freezed_provider_value_notifier/lib/app.dart b/freezed_provider_value_notifier/lib/app.dart index 3b4bb063..4a9e7a8f 100644 --- a/freezed_provider_value_notifier/lib/app.dart +++ b/freezed_provider_value_notifier/lib/app.dart @@ -1,13 +1,8 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:freezed_provider_value_notifier/value_notifier_provider.dart'; -import 'package:meta/meta.dart'; import 'package:freezed_provider_value_notifier/add_todo_screen.dart'; import 'package:freezed_provider_value_notifier/localization.dart'; import 'package:freezed_provider_value_notifier/todo_list_model.dart'; +import 'package:freezed_provider_value_notifier/value_notifier_provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -16,16 +11,15 @@ import 'home/home_screen.dart'; class ProviderApp extends StatelessWidget { final TodosRepository repository; - ProviderApp({ - @required this.repository, - }); + const ProviderApp({super.key, required this.repository}); @override Widget build(BuildContext context) { return ValueNotifierProvider( create: (_) => TodoListController(todosRepository: repository), child: MaterialApp( - theme: ArchSampleTheme.theme, + theme: ArchSampleTheme.lightTheme, + darkTheme: ArchSampleTheme.darkTheme, localizationsDelegates: [ ArchSampleLocalizationsDelegate(), ProviderLocalizationsDelegate(), diff --git a/freezed_provider_value_notifier/lib/details_screen.dart b/freezed_provider_value_notifier/lib/details_screen.dart index 7841a375..9a356c0d 100644 --- a/freezed_provider_value_notifier/lib/details_screen.dart +++ b/freezed_provider_value_notifier/lib/details_screen.dart @@ -1,18 +1,17 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:freezed_provider_value_notifier/todo_list_model.dart'; +import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'edit_todo_screen.dart'; import 'models.dart'; -import 'todo_list_model.dart'; class DetailsScreen extends StatelessWidget { final String id; final VoidCallback onRemove; - const DetailsScreen({@required this.id, @required this.onRemove}) - : super(key: ArchSampleKeys.todoDetailsScreen); + const DetailsScreen({required this.id, required this.onRemove}) + : super(key: ArchSampleKeys.todoDetailsScreen); @override Widget build(BuildContext context) { @@ -25,13 +24,15 @@ class DetailsScreen extends StatelessWidget { tooltip: ArchSampleLocalizations.of(context).deleteTodo, icon: const Icon(Icons.delete), onPressed: onRemove, - ) + ), ], ), - body: Selector( + body: Selector( selector: (context, model) => model.todoById(id), shouldRebuild: (prev, next) => next != null, - builder: (context, todo, _) { + builder: (context, t, _) { + final todo = t!; + return Padding( padding: const EdgeInsets.all(16.0), child: ListView( @@ -45,9 +46,9 @@ class DetailsScreen extends StatelessWidget { key: ArchSampleKeys.detailsTodoItemCheckbox, value: todo.complete, onChanged: (complete) { - context - .read() - .updateTodo(todo.copy(complete: !todo.complete)); + context.read().updateTodo( + todo.copy(complete: !todo.complete), + ); }, ), ), @@ -63,14 +64,14 @@ class DetailsScreen extends StatelessWidget { child: Text( todo.task, key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, ), ), Text( todo.note, key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) + style: Theme.of(context).textTheme.titleMedium, + ), ], ), ), @@ -86,18 +87,22 @@ class DetailsScreen extends StatelessWidget { onPressed: () { Navigator.push( context, - MaterialPageRoute( - builder: (context) => EditTodoScreen( - id: id, - onEdit: (task, note) { - context.read().updateTodo(context - .read() - .todoById(id) - ?.copy(task: task, note: note)); + MaterialPageRoute( + builder: (context) { + return EditTodoScreen( + id: id, + onEdit: (task, note) { + context.read().updateTodo( + context + .read() + .todoById(id)! + .copy(task: task, note: note), + ); - return Navigator.pop(context); - }, - ), + return Navigator.pop(context); + }, + ); + }, ), ); }, diff --git a/freezed_provider_value_notifier/lib/edit_todo_screen.dart b/freezed_provider_value_notifier/lib/edit_todo_screen.dart index ad7b32fa..67ea7413 100644 --- a/freezed_provider_value_notifier/lib/edit_todo_screen.dart +++ b/freezed_provider_value_notifier/lib/edit_todo_screen.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:freezed_provider_value_notifier/todo_list_model.dart'; +import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; class EditTodoScreen extends StatefulWidget { @@ -8,18 +8,19 @@ class EditTodoScreen extends StatefulWidget { final String id; const EditTodoScreen({ - @required this.id, - @required this.onEdit, - }) : super(key: ArchSampleKeys.editTodoScreen); + super.key = ArchSampleKeys.editTodoScreen, + required this.id, + required this.onEdit, + }); @override - _EditTodoScreenState createState() => _EditTodoScreenState(); + EditTodoScreenState createState() => EditTodoScreenState(); } -class _EditTodoScreenState extends State { +class EditTodoScreenState extends State { final _formKey = GlobalKey(); - TextEditingController _taskController; - TextEditingController _noteController; + late TextEditingController _taskController; + late TextEditingController _noteController; @override void initState() { @@ -49,12 +50,12 @@ class _EditTodoScreenState extends State { TextFormField( controller: _taskController, key: ArchSampleKeys.taskField, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, decoration: InputDecoration( hintText: ArchSampleLocalizations.of(context).newTodoHint, ), validator: (val) { - return val.trim().isEmpty + return val != null && val.trim().isEmpty ? ArchSampleLocalizations.of(context).emptyTodoError : null; }, @@ -66,7 +67,7 @@ class _EditTodoScreenState extends State { hintText: ArchSampleLocalizations.of(context).notesHint, ), maxLines: 10, - ) + ), ], ), ), @@ -75,8 +76,8 @@ class _EditTodoScreenState extends State { key: ArchSampleKeys.saveTodoFab, tooltip: ArchSampleLocalizations.of(context).saveChanges, onPressed: () { - if (_formKey.currentState.validate()) { - _formKey.currentState.save(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); widget.onEdit(_taskController.text, _noteController.text); } }, diff --git a/freezed_provider_value_notifier/lib/home/extra_actions_button.dart b/freezed_provider_value_notifier/lib/home/extra_actions_button.dart index 5975c7f0..0538d1bf 100644 --- a/freezed_provider_value_notifier/lib/home/extra_actions_button.dart +++ b/freezed_provider_value_notifier/lib/home/extra_actions_button.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; @@ -9,9 +5,7 @@ import 'package:todos_app_core/todos_app_core.dart'; import '../todo_list_model.dart'; class ExtraActionsButton extends StatelessWidget { - const ExtraActionsButton({ - Key key, - }) : super(key: key); + const ExtraActionsButton({super.key}); @override Widget build(BuildContext context) { @@ -34,9 +28,11 @@ class ExtraActionsButton extends StatelessWidget { PopupMenuItem( key: ArchSampleKeys.toggleAll, value: ExtraAction.toggleAllComplete, - child: Text(model.hasActiveTodos - ? ArchSampleLocalizations.of(context).markAllComplete - : ArchSampleLocalizations.of(context).markAllIncomplete), + child: Text( + model.hasActiveTodos + ? ArchSampleLocalizations.of(context).markAllComplete + : ArchSampleLocalizations.of(context).markAllIncomplete, + ), ), PopupMenuItem( key: ArchSampleKeys.clearCompleted, diff --git a/freezed_provider_value_notifier/lib/home/filter_button.dart b/freezed_provider_value_notifier/lib/home/filter_button.dart index 701f4382..fb2e7a12 100644 --- a/freezed_provider_value_notifier/lib/home/filter_button.dart +++ b/freezed_provider_value_notifier/lib/home/filter_button.dart @@ -1,16 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:freezed_provider_value_notifier/todo_list_model.dart'; +import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; class FilterButton extends StatelessWidget { final bool isActive; - const FilterButton({this.isActive, Key key}) : super(key: key); + const FilterButton({super.key, required this.isActive}); @override Widget build(BuildContext context) { @@ -37,20 +33,23 @@ class FilterButton extends StatelessWidget { } List> _items( - BuildContext context, TodoList store) { - final activeStyle = Theme.of(context) - .textTheme - .body1 - .copyWith(color: Theme.of(context).accentColor); - final defaultStyle = Theme.of(context).textTheme.body1; + BuildContext context, + TodoList store, + ) { + final defaultStyle = Theme.of(context).textTheme.bodyMedium!; + final activeStyle = defaultStyle.copyWith( + color: Theme.of(context).colorScheme.secondary, + ); + return [ PopupMenuItem( key: ArchSampleKeys.allFilter, value: VisibilityFilter.all, child: Text( ArchSampleLocalizations.of(context).showAll, - style: - store.filter == VisibilityFilter.all ? activeStyle : defaultStyle, + style: store.filter == VisibilityFilter.all + ? activeStyle + : defaultStyle, ), ), PopupMenuItem( diff --git a/freezed_provider_value_notifier/lib/home/home_screen.dart b/freezed_provider_value_notifier/lib/home/home_screen.dart index cc9fec01..2bf31941 100644 --- a/freezed_provider_value_notifier/lib/home/home_screen.dart +++ b/freezed_provider_value_notifier/lib/home/home_screen.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart' hide Action; -import 'package:provider/provider.dart'; import 'package:freezed_provider_value_notifier/home/stats_view.dart'; import 'package:freezed_provider_value_notifier/home/todo_list_view.dart'; import 'package:freezed_provider_value_notifier/localization.dart'; import 'package:freezed_provider_value_notifier/todo_list_model.dart'; +import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; import '../models.dart'; @@ -11,13 +11,13 @@ import 'extra_actions_button.dart'; import 'filter_button.dart'; class HomeScreen extends StatefulWidget { - const HomeScreen(); + const HomeScreen({super.key}); @override - _HomeScreenState createState() => _HomeScreenState(); + HomeScreenState createState() => HomeScreenState(); } -class _HomeScreenState extends State { +class HomeScreenState extends State { // Because the state of the tabs is only a concern to the HomeScreen Widget, // it is stored as local state rather than in the TodoListModel. final _tab = ValueNotifier(_HomeScreenTab.todos); @@ -36,9 +36,8 @@ class _HomeScreenState extends State { actions: [ ValueListenableBuilder<_HomeScreenTab>( valueListenable: _tab, - builder: (_, tab, __) => FilterButton( - isActive: tab == _HomeScreenTab.todos, - ), + builder: (_, tab, _) => + FilterButton(isActive: tab == _HomeScreenTab.todos), ), const ExtraActionsButton(), ], @@ -67,12 +66,11 @@ class _HomeScreenState extends State { case _HomeScreenTab.stats: return const StatsView(); case _HomeScreenTab.todos: - default: return TodoListView( onRemove: (context, todo) { - context - .read() - .removeTodoWithId(todo.id); + context.read().removeTodoWithId( + todo.id, + ); _showUndoSnackbar(context, todo); }, ); @@ -91,11 +89,11 @@ class _HomeScreenState extends State { items: [ BottomNavigationBarItem( icon: Icon(Icons.list, key: ArchSampleKeys.todoTab), - title: Text(ArchSampleLocalizations.of(context).todos), + label: ArchSampleLocalizations.of(context).todos, ), BottomNavigationBarItem( icon: Icon(Icons.show_chart, key: ArchSampleKeys.statsTab), - title: Text(ArchSampleLocalizations.of(context).stats), + label: ArchSampleLocalizations.of(context).stats, ), ], ); @@ -105,7 +103,7 @@ class _HomeScreenState extends State { } void _showUndoSnackbar(BuildContext context, Todo todo) { - Scaffold.of(context).showSnackBar( + ScaffoldMessenger.of(context).showSnackBar( SnackBar( key: ArchSampleKeys.snackbar, duration: const Duration(seconds: 2), diff --git a/freezed_provider_value_notifier/lib/home/stats_view.dart b/freezed_provider_value_notifier/lib/home/stats_view.dart index 868b7b10..6b11dd88 100644 --- a/freezed_provider_value_notifier/lib/home/stats_view.dart +++ b/freezed_provider_value_notifier/lib/home/stats_view.dart @@ -1,11 +1,10 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:freezed_provider_value_notifier/todo_list_model.dart'; +import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; class StatsView extends StatelessWidget { - const StatsView(); + const StatsView({super.key}); @override Widget build(BuildContext context) { @@ -17,7 +16,7 @@ class StatsView extends StatelessWidget { padding: const EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -27,7 +26,7 @@ class StatsView extends StatelessWidget { builder: (context, numCompleted, _) => Text( '$numCompleted', key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ), @@ -35,7 +34,7 @@ class StatsView extends StatelessWidget { padding: const EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -45,10 +44,10 @@ class StatsView extends StatelessWidget { builder: (context, numActive, _) => Text( '$numActive', key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), - ) + ), ], ), ); diff --git a/freezed_provider_value_notifier/lib/home/todo_list_view.dart b/freezed_provider_value_notifier/lib/home/todo_list_view.dart index 806e926e..0713250d 100644 --- a/freezed_provider_value_notifier/lib/home/todo_list_view.dart +++ b/freezed_provider_value_notifier/lib/home/todo_list_view.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:freezed_provider_value_notifier/todo_list_model.dart'; +import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; import '../details_screen.dart'; @@ -9,7 +9,7 @@ import '../models.dart'; class TodoListView extends StatelessWidget { final void Function(BuildContext context, Todo todo) onRemove; - TodoListView({Key key, @required this.onRemove}) : super(key: key); + const TodoListView({super.key, required this.onRemove}); @override Widget build(BuildContext context) { @@ -29,10 +29,10 @@ class TodoListView extends StatelessWidget { onTap: () { Navigator.push( context, - MaterialPageRoute( + MaterialPageRoute( builder: (_) { return DetailsScreen( - id: todo?.id, + id: todo.id, onRemove: () { Navigator.pop(context); onRemove(context, todo); @@ -46,22 +46,22 @@ class TodoListView extends StatelessWidget { key: ArchSampleKeys.todoItemCheckbox(todo.id), value: todo.complete, onChanged: (complete) { - context - .read() - .updateTodo(todo.copy(complete: complete)); + context.read().updateTodo( + todo.copy(complete: complete), + ); }, ), title: Text( todo.task, key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), subtitle: Text( todo.note, key: ArchSampleKeys.todoItemNote(todo.id), maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ); diff --git a/freezed_provider_value_notifier/lib/localization.dart b/freezed_provider_value_notifier/lib/localization.dart index 9ca0b67d..f18a6a0c 100644 --- a/freezed_provider_value_notifier/lib/localization.dart +++ b/freezed_provider_value_notifier/lib/localization.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; @@ -9,7 +5,9 @@ import 'package:flutter/material.dart'; class ProviderLocalizations { static ProviderLocalizations of(BuildContext context) { return Localizations.of( - context, ProviderLocalizations); + context, + ProviderLocalizations, + )!; } String get appTitle => 'Provider Example'; diff --git a/freezed_provider_value_notifier/lib/main.dart b/freezed_provider_value_notifier/lib/main.dart index 503a7da5..306c152e 100644 --- a/freezed_provider_value_notifier/lib/main.dart +++ b/freezed_provider_value_notifier/lib/main.dart @@ -1,22 +1,19 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:freezed_provider_value_notifier/app.dart'; import 'package:flutter/material.dart'; -import 'package:key_value_store_flutter/key_value_store_flutter.dart'; +import 'package:freezed_provider_value_notifier/app.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(ProviderApp( - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'change_notifier_provider_todos', - FlutterKeyValueStore(await SharedPreferences.getInstance()), + runApp( + ProviderApp( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'change_notifier_provider_todos', + await SharedPreferences.getInstance(), + ), ), ), - )); + ); } diff --git a/freezed_provider_value_notifier/lib/main_web.dart b/freezed_provider_value_notifier/lib/main_web.dart deleted file mode 100644 index cd6490a2..00000000 --- a/freezed_provider_value_notifier/lib/main_web.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:html'; - -import 'package:freezed_provider_value_notifier/app.dart'; -import 'package:flutter/material.dart'; -import 'package:key_value_store_web/key_value_store_web.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(ProviderApp( - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'change_notifier_provider', - WebKeyValueStore(window.localStorage), - ), - ), - )); -} diff --git a/freezed_provider_value_notifier/lib/models.dart b/freezed_provider_value_notifier/lib/models.dart index e6b5b627..ceaf4e1b 100644 --- a/freezed_provider_value_notifier/lib/models.dart +++ b/freezed_provider_value_notifier/lib/models.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -11,8 +7,8 @@ class Todo { final String note; final String task; - Todo(this.task, {this.complete = false, this.note = '', String id}) - : id = id ?? Uuid().generateV4(); + Todo(this.task, {this.complete = false, this.note = '', String? id}) + : id = id ?? Uuid().generateV4(); @override int get hashCode => @@ -40,13 +36,13 @@ class Todo { static Todo fromEntity(TodoEntity entity) { return Todo( entity.task, - complete: entity.complete ?? false, + complete: entity.complete, note: entity.note, id: entity.id, ); } - Todo copy({String task, bool complete, String note, String id}) { + Todo copy({String? task, bool? complete, String? note, String? id}) { return Todo( task ?? this.task, complete: complete ?? this.complete, diff --git a/freezed_provider_value_notifier/lib/todo_list_model.dart b/freezed_provider_value_notifier/lib/todo_list_model.dart index 8f3da9dc..db4dc478 100644 --- a/freezed_provider_value_notifier/lib/todo_list_model.dart +++ b/freezed_provider_value_notifier/lib/todo_list_model.dart @@ -1,10 +1,5 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/widgets.dart'; -import 'package:flutter/foundation.dart'; import 'package:collection/collection.dart'; +import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_provider_value_notifier/models.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -17,50 +12,42 @@ enum VisibilityFilter { all, active, completed } abstract class TodoList with _$TodoList { factory TodoList( List todos, { - @required VisibilityFilter filter, - @required bool loading, + required VisibilityFilter filter, + required bool loading, }) = TodoListState; +} + +extension TodoById on TodoList { + Todo? todoById(String id) => todos.firstWhereOrNull((it) => it.id == id); - @late int get numCompleted => todos.where((Todo todo) => todo.complete).toList().length; - @late bool get hasCompleted => numCompleted > 0; - @late int get numActive => todos.where((Todo todo) => !todo.complete).toList().length; - @late bool get hasActiveTodos => numActive > 0; - @late List get filteredTodos => todos.where((todo) { - switch (filter) { - case VisibilityFilter.active: - return !todo.complete; - case VisibilityFilter.completed: - return todo.complete; - case VisibilityFilter.all: - default: - return true; - } - }).toList(); -} - -extension TodoById on TodoList { - Todo todoById(String id) => - todos.firstWhere((it) => it.id == id, orElse: () => null); + switch (filter) { + case VisibilityFilter.active: + return !todo.complete; + case VisibilityFilter.completed: + return todo.complete; + case VisibilityFilter.all: + return true; + } + }).toList(); } class TodoListController extends ValueNotifier { TodoListController({ VisibilityFilter filter = VisibilityFilter.all, - @required this.todosRepository, + required this.todosRepository, List todos = const [], - }) : assert(todosRepository != null), - super(TodoList(todos, filter: filter, loading: false)) { + }) : super(TodoList(todos, filter: filter, loading: false)) { _loadTodos(); } @@ -74,8 +61,9 @@ class TodoListController extends ValueNotifier { @protected set value(TodoList state) { if (!const DeepCollectionEquality().equals(state.todos, value.todos)) { - todosRepository - .saveTodos(state.todos.map((it) => it.toEntity()).toList()); + todosRepository.saveTodos( + state.todos.map((it) => it.toEntity()).toList(), + ); } super.value = state; } @@ -86,7 +74,9 @@ class TodoListController extends ValueNotifier { try { final todos = await todosRepository.loadTodos(); value = (value.copyWith( - todos: todos.map(Todo.fromEntity).toList(), loading: false)); + todos: todos.map(Todo.fromEntity).toList(), + loading: false, + )); } catch (_) { value = (value.copyWith(loading: false)); } @@ -97,23 +87,30 @@ class TodoListController extends ValueNotifier { } void updateTodo(Todo updatedTodo) { - value = value.copyWith(todos: [ - for (final todo in value.todos) - if (todo.id == updatedTodo.id) updatedTodo else todo, - ]); + value = value.copyWith( + todos: [ + for (final todo in value.todos) + if (todo.id == updatedTodo.id) updatedTodo else todo, + ], + ); } void removeTodoWithId(String id) { - value = value.copyWith(todos: [ - for (final todo in value.todos) if (todo.id != id) todo, - ]); + value = value.copyWith( + todos: [ + for (final todo in value.todos) + if (todo.id != id) todo, + ], + ); } void toggleAll() { final allComplete = value.todos.every((todo) => todo.complete); - value = value.copyWith(todos: [ - for (final todo in value.todos) todo.copy(complete: !allComplete), - ]); + value = value.copyWith( + todos: [ + for (final todo in value.todos) todo.copy(complete: !allComplete), + ], + ); } void clearCompleted() { diff --git a/freezed_provider_value_notifier/lib/todo_list_model.freezed.dart b/freezed_provider_value_notifier/lib/todo_list_model.freezed.dart index c590dbcb..07779511 100644 --- a/freezed_provider_value_notifier/lib/todo_list_model.freezed.dart +++ b/freezed_provider_value_notifier/lib/todo_list_model.freezed.dart @@ -1,5 +1,7 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: deprecated_member_use_from_same_package +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark part of 'todo_list_model.dart'; @@ -7,165 +9,287 @@ part of 'todo_list_model.dart'; // FreezedGenerator // ************************************************************************** -mixin _$TodoList { - List get todos; - VisibilityFilter get filter; - bool get loading; - - TodoList copyWith({List todos, VisibilityFilter filter, bool loading}); -} - -class _$TodoListState with DiagnosticableTreeMixin implements TodoListState { - _$TodoListState(this.todos, {@required this.filter, @required this.loading}) - : assert(todos != null), - assert(filter != null), - assert(loading != null); - - @override - final List todos; - @override - final VisibilityFilter filter; - @override - final bool loading; - bool _didnumCompleted = false; - int _numCompleted; - - @override - int get numCompleted { - if (_didnumCompleted == false) { - _didnumCompleted = true; - _numCompleted = todos.where((Todo todo) => todo.complete).toList().length; - } - return _numCompleted; - } - - bool _didhasCompleted = false; - bool _hasCompleted; - - @override - bool get hasCompleted { - if (_didhasCompleted == false) { - _didhasCompleted = true; - _hasCompleted = numCompleted > 0; - } - return _hasCompleted; - } - - bool _didnumActive = false; - int _numActive; - - @override - int get numActive { - if (_didnumActive == false) { - _didnumActive = true; - _numActive = todos.where((Todo todo) => !todo.complete).toList().length; - } - return _numActive; - } - - bool _didhasActiveTodos = false; - bool _hasActiveTodos; - - @override - bool get hasActiveTodos { - if (_didhasActiveTodos == false) { - _didhasActiveTodos = true; - _hasActiveTodos = numActive > 0; - } - return _hasActiveTodos; - } - - bool _didfilteredTodos = false; - List _filteredTodos; - - @override - List get filteredTodos { - if (_didfilteredTodos == false) { - _didfilteredTodos = true; - _filteredTodos = todos.where((todo) { - switch (filter) { - case VisibilityFilter.active: - return !todo.complete; - case VisibilityFilter.completed: - return todo.complete; - case VisibilityFilter.all: - default: - return true; - } - }).toList(); - } - return _filteredTodos; - } - - @override - String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { - return 'TodoList(todos: $todos, filter: $filter, loading: $loading, numCompleted: $numCompleted, hasCompleted: $hasCompleted, numActive: $numActive, hasActiveTodos: $hasActiveTodos, filteredTodos: $filteredTodos)'; - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('type', 'TodoList')) - ..add(DiagnosticsProperty('todos', todos)) - ..add(DiagnosticsProperty('filter', filter)) - ..add(DiagnosticsProperty('loading', loading)) - ..add(DiagnosticsProperty('numCompleted', numCompleted)) - ..add(DiagnosticsProperty('hasCompleted', hasCompleted)) - ..add(DiagnosticsProperty('numActive', numActive)) - ..add(DiagnosticsProperty('hasActiveTodos', hasActiveTodos)) - ..add(DiagnosticsProperty('filteredTodos', filteredTodos)); - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other is TodoListState && - (identical(other.todos, todos) || - const DeepCollectionEquality().equals(other.todos, todos)) && - (identical(other.filter, filter) || - const DeepCollectionEquality().equals(other.filter, filter)) && - (identical(other.loading, loading) || - const DeepCollectionEquality().equals(other.loading, loading))); - } - - @override - int get hashCode => - runtimeType.hashCode ^ - todos.hashCode ^ - filter.hashCode ^ - loading.hashCode; - - @override - _$TodoListState copyWith({ - Object todos = freezed, - Object filter = freezed, - Object loading = freezed, - }) { - assert(todos != null); - assert(filter != null); - assert(loading != null); - return _$TodoListState( - todos == freezed ? this.todos : todos as List, - filter: filter == freezed ? this.filter : filter as VisibilityFilter, - loading: loading == freezed ? this.loading : loading as bool, - ); - } -} - -abstract class TodoListState implements TodoList { - factory TodoListState(List todos, - {@required VisibilityFilter filter, - @required bool loading}) = _$TodoListState; - - @override - List get todos; - @override - VisibilityFilter get filter; - @override - bool get loading; - - @override - TodoListState copyWith( - {List todos, VisibilityFilter filter, bool loading}); +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$TodoList implements DiagnosticableTreeMixin { + + List get todos; VisibilityFilter get filter; bool get loading; +/// Create a copy of TodoList +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$TodoListCopyWith get copyWith => _$TodoListCopyWithImpl(this as TodoList, _$identity); + + +@override +void debugFillProperties(DiagnosticPropertiesBuilder properties) { + properties + ..add(DiagnosticsProperty('type', 'TodoList')) + ..add(DiagnosticsProperty('todos', todos))..add(DiagnosticsProperty('filter', filter))..add(DiagnosticsProperty('loading', loading)); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is TodoList&&const DeepCollectionEquality().equals(other.todos, todos)&&(identical(other.filter, filter) || other.filter == filter)&&(identical(other.loading, loading) || other.loading == loading)); +} + + +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(todos),filter,loading); + +@override +String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) { + return 'TodoList(todos: $todos, filter: $filter, loading: $loading)'; +} + + +} + +/// @nodoc +abstract mixin class $TodoListCopyWith<$Res> { + factory $TodoListCopyWith(TodoList value, $Res Function(TodoList) _then) = _$TodoListCopyWithImpl; +@useResult +$Res call({ + List todos, VisibilityFilter filter, bool loading +}); + + + + +} +/// @nodoc +class _$TodoListCopyWithImpl<$Res> + implements $TodoListCopyWith<$Res> { + _$TodoListCopyWithImpl(this._self, this._then); + + final TodoList _self; + final $Res Function(TodoList) _then; + +/// Create a copy of TodoList +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? todos = null,Object? filter = null,Object? loading = null,}) { + return _then(_self.copyWith( +todos: null == todos ? _self.todos : todos // ignore: cast_nullable_to_non_nullable +as List,filter: null == filter ? _self.filter : filter // ignore: cast_nullable_to_non_nullable +as VisibilityFilter,loading: null == loading ? _self.loading : loading // ignore: cast_nullable_to_non_nullable +as bool, + )); } + +} + + +/// Adds pattern-matching-related methods to [TodoList]. +extension TodoListPatterns on TodoList { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( TodoListState value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case TodoListState() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( TodoListState value) $default,){ +final _that = this; +switch (_that) { +case TodoListState(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( TodoListState value)? $default,){ +final _that = this; +switch (_that) { +case TodoListState() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( List todos, VisibilityFilter filter, bool loading)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case TodoListState() when $default != null: +return $default(_that.todos,_that.filter,_that.loading);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( List todos, VisibilityFilter filter, bool loading) $default,) {final _that = this; +switch (_that) { +case TodoListState(): +return $default(_that.todos,_that.filter,_that.loading);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( List todos, VisibilityFilter filter, bool loading)? $default,) {final _that = this; +switch (_that) { +case TodoListState() when $default != null: +return $default(_that.todos,_that.filter,_that.loading);case _: + return null; + +} +} + +} + +/// @nodoc + + +class TodoListState with DiagnosticableTreeMixin implements TodoList { + TodoListState(final List todos, {required this.filter, required this.loading}): _todos = todos; + + + final List _todos; +@override List get todos { + if (_todos is EqualUnmodifiableListView) return _todos; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_todos); +} + +@override final VisibilityFilter filter; +@override final bool loading; + +/// Create a copy of TodoList +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$TodoListStateCopyWith get copyWith => _$TodoListStateCopyWithImpl(this, _$identity); + + +@override +void debugFillProperties(DiagnosticPropertiesBuilder properties) { + properties + ..add(DiagnosticsProperty('type', 'TodoList')) + ..add(DiagnosticsProperty('todos', todos))..add(DiagnosticsProperty('filter', filter))..add(DiagnosticsProperty('loading', loading)); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is TodoListState&&const DeepCollectionEquality().equals(other._todos, _todos)&&(identical(other.filter, filter) || other.filter == filter)&&(identical(other.loading, loading) || other.loading == loading)); +} + + +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_todos),filter,loading); + +@override +String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) { + return 'TodoList(todos: $todos, filter: $filter, loading: $loading)'; +} + + +} + +/// @nodoc +abstract mixin class $TodoListStateCopyWith<$Res> implements $TodoListCopyWith<$Res> { + factory $TodoListStateCopyWith(TodoListState value, $Res Function(TodoListState) _then) = _$TodoListStateCopyWithImpl; +@override @useResult +$Res call({ + List todos, VisibilityFilter filter, bool loading +}); + + + + +} +/// @nodoc +class _$TodoListStateCopyWithImpl<$Res> + implements $TodoListStateCopyWith<$Res> { + _$TodoListStateCopyWithImpl(this._self, this._then); + + final TodoListState _self; + final $Res Function(TodoListState) _then; + +/// Create a copy of TodoList +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? todos = null,Object? filter = null,Object? loading = null,}) { + return _then(TodoListState( +null == todos ? _self._todos : todos // ignore: cast_nullable_to_non_nullable +as List,filter: null == filter ? _self.filter : filter // ignore: cast_nullable_to_non_nullable +as VisibilityFilter,loading: null == loading ? _self.loading : loading // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + + +} + +// dart format on diff --git a/freezed_provider_value_notifier/lib/value_notifier_provider.dart b/freezed_provider_value_notifier/lib/value_notifier_provider.dart index 53305856..2b7dd067 100644 --- a/freezed_provider_value_notifier/lib/value_notifier_provider.dart +++ b/freezed_provider_value_notifier/lib/value_notifier_provider.dart @@ -1,5 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter/widgets.dart'; import 'package:provider/provider.dart'; import 'package:provider/single_child_widget.dart'; @@ -8,13 +7,12 @@ import 'package:provider/single_child_widget.dart'; class ValueNotifierProvider, Value> extends SingleChildStatelessWidget { - ValueNotifierProvider({@required this.create, Widget child}) - : super(child: child); + const ValueNotifierProvider({super.key, required this.create, super.child}); final Create create; @override - Widget buildWithChild(BuildContext context, Widget child) { + Widget buildWithChild(BuildContext context, Widget? child) { return InheritedProvider( create: create, dispose: (context, Controller controller) => controller.dispose(), @@ -22,7 +20,7 @@ class ValueNotifierProvider, Value> create: (context) => context.read(), startListening: (context, setState, controller, _) { setState(controller.value); - final listener = () => setState(controller.value); + void listener() => setState(controller.value); controller.addListener(listener); return () => controller.removeListener(listener); }, diff --git a/freezed_provider_value_notifier/linux/.gitignore b/freezed_provider_value_notifier/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/freezed_provider_value_notifier/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/freezed_provider_value_notifier/linux/CMakeLists.txt b/freezed_provider_value_notifier/linux/CMakeLists.txt new file mode 100644 index 00000000..40c0900f --- /dev/null +++ b/freezed_provider_value_notifier/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +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 "freezed_provider_value_notifier") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.freezed_provider_value_notifier") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +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() + +# 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() + +# 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_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# 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 +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# 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() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +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) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/freezed_provider_value_notifier/linux/flutter/CMakeLists.txt b/freezed_provider_value_notifier/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/freezed_provider_value_notifier/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +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. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# 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/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter 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. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/freezed_provider_value_notifier/linux/flutter/generated_plugin_registrant.cc b/freezed_provider_value_notifier/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e71a16d2 --- /dev/null +++ b/freezed_provider_value_notifier/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/freezed_provider_value_notifier/linux/flutter/generated_plugin_registrant.h b/freezed_provider_value_notifier/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/freezed_provider_value_notifier/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/freezed_provider_value_notifier/linux/flutter/generated_plugins.cmake b/freezed_provider_value_notifier/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/freezed_provider_value_notifier/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + 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}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/freezed_provider_value_notifier/linux/runner/CMakeLists.txt b/freezed_provider_value_notifier/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/freezed_provider_value_notifier/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "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 +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/freezed_provider_value_notifier/linux/runner/main.cc b/freezed_provider_value_notifier/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/freezed_provider_value_notifier/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/freezed_provider_value_notifier/linux/runner/my_application.cc b/freezed_provider_value_notifier/linux/runner/my_application.cc new file mode 100644 index 00000000..a0fc91b9 --- /dev/null +++ b/freezed_provider_value_notifier/linux/runner/my_application.cc @@ -0,0 +1,144 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView *view) +{ + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // 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 + // desktop). + // 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. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "freezed_provider_value_notifier"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "freezed_provider_value_notifier"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/freezed_provider_value_notifier/linux/runner/my_application.h b/freezed_provider_value_notifier/linux/runner/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/freezed_provider_value_notifier/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/freezed_provider_value_notifier/macos/.gitignore b/freezed_provider_value_notifier/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/freezed_provider_value_notifier/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/freezed_provider_value_notifier/macos/Flutter/Flutter-Debug.xcconfig b/freezed_provider_value_notifier/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/freezed_provider_value_notifier/macos/Flutter/Flutter-Release.xcconfig b/freezed_provider_value_notifier/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/freezed_provider_value_notifier/macos/Flutter/GeneratedPluginRegistrant.swift b/freezed_provider_value_notifier/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b8e2b22f --- /dev/null +++ b/freezed_provider_value_notifier/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/freezed_provider_value_notifier/macos/Podfile b/freezed_provider_value_notifier/macos/Podfile new file mode 100644 index 00000000..ff5ddb3b --- /dev/null +++ b/freezed_provider_value_notifier/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/freezed_provider_value_notifier/macos/Podfile.lock b/freezed_provider_value_notifier/macos/Podfile.lock new file mode 100644 index 00000000..d2f9a639 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Podfile.lock @@ -0,0 +1,30 @@ +PODS: + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + +SPEC CHECKSUMS: + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.16.2 diff --git a/freezed_provider_value_notifier/macos/Runner.xcodeproj/project.pbxproj b/freezed_provider_value_notifier/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..d1c04506 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 3A3591511D8739FC5EA309CB /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E854EB9A64F00ECF984C1CB /* Pods_RunnerTests.framework */; }; + 3D7637D135CFCD418C85B762 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5AA1B52C1BAEF2F148DD5342 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 098CA664BD1597035C2CEDD1 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 1AAFE64F22632A853B45FAA0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 1E854EB9A64F00ECF984C1CB /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* freezed_provider_value_notifier.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = freezed_provider_value_notifier.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 37C35DA4EC4C39DA45256CE6 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 5AA1B52C1BAEF2F148DD5342 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6C9A6ADFA7C9FBF67F85B509 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 8F6040DD3C8C6F63E934AECB /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + D20A115EA97DF290E32E28E3 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3A3591511D8739FC5EA309CB /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D7637D135CFCD418C85B762 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + AE2A868EB465F4FCA12C9ED2 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* freezed_provider_value_notifier.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + AE2A868EB465F4FCA12C9ED2 /* Pods */ = { + isa = PBXGroup; + children = ( + 098CA664BD1597035C2CEDD1 /* Pods-Runner.debug.xcconfig */, + 6C9A6ADFA7C9FBF67F85B509 /* Pods-Runner.release.xcconfig */, + 1AAFE64F22632A853B45FAA0 /* Pods-Runner.profile.xcconfig */, + D20A115EA97DF290E32E28E3 /* Pods-RunnerTests.debug.xcconfig */, + 37C35DA4EC4C39DA45256CE6 /* Pods-RunnerTests.release.xcconfig */, + 8F6040DD3C8C6F63E934AECB /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5AA1B52C1BAEF2F148DD5342 /* Pods_Runner.framework */, + 1E854EB9A64F00ECF984C1CB /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + D983E28EC4EA86860B94BDC1 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 47A6D86E9EFD6AD78ADBF340 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + CD1175C88C2F7DA9A7473A87 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* freezed_provider_value_notifier.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 47A6D86E9EFD6AD78ADBF340 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + CD1175C88C2F7DA9A7473A87 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + D983E28EC4EA86860B94BDC1 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D20A115EA97DF290E32E28E3 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.freezedProviderValueNotifier.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/freezed_provider_value_notifier.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/freezed_provider_value_notifier"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 37C35DA4EC4C39DA45256CE6 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.freezedProviderValueNotifier.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/freezed_provider_value_notifier.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/freezed_provider_value_notifier"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8F6040DD3C8C6F63E934AECB /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.freezedProviderValueNotifier.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/freezed_provider_value_notifier.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/freezed_provider_value_notifier"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/freezed_provider_value_notifier/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/freezed_provider_value_notifier/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/freezed_provider_value_notifier/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/freezed_provider_value_notifier/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..447c86fe --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/freezed_provider_value_notifier/macos/Runner.xcworkspace/contents.xcworkspacedata b/freezed_provider_value_notifier/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/freezed_provider_value_notifier/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/freezed_provider_value_notifier/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/freezed_provider_value_notifier/macos/Runner/AppDelegate.swift b/freezed_provider_value_notifier/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/freezed_provider_value_notifier/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/freezed_provider_value_notifier/macos/Runner/Base.lproj/MainMenu.xib b/freezed_provider_value_notifier/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/freezed_provider_value_notifier/macos/Runner/Configs/AppInfo.xcconfig b/freezed_provider_value_notifier/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..e35528b6 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// 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 +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = freezed_provider_value_notifier + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.freezedProviderValueNotifier + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/freezed_provider_value_notifier/macos/Runner/Configs/Debug.xcconfig b/freezed_provider_value_notifier/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/freezed_provider_value_notifier/macos/Runner/Configs/Release.xcconfig b/freezed_provider_value_notifier/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/freezed_provider_value_notifier/macos/Runner/Configs/Warnings.xcconfig b/freezed_provider_value_notifier/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/freezed_provider_value_notifier/macos/Runner/DebugProfile.entitlements b/freezed_provider_value_notifier/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/freezed_provider_value_notifier/macos/Runner/Info.plist b/freezed_provider_value_notifier/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/freezed_provider_value_notifier/macos/Runner/MainFlutterWindow.swift b/freezed_provider_value_notifier/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/freezed_provider_value_notifier/macos/Runner/Release.entitlements b/freezed_provider_value_notifier/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/freezed_provider_value_notifier/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/freezed_provider_value_notifier/macos/RunnerTests/RunnerTests.swift b/freezed_provider_value_notifier/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/freezed_provider_value_notifier/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/freezed_provider_value_notifier/pubspec.yaml b/freezed_provider_value_notifier/pubspec.yaml index c27a295e..a2daa1a9 100644 --- a/freezed_provider_value_notifier/pubspec.yaml +++ b/freezed_provider_value_notifier/pubspec.yaml @@ -2,34 +2,37 @@ name: freezed_provider_value_notifier description: A new Flutter project. version: 1.0.0+1 +publish_to: "none" environment: - sdk: ">=2.6.0 <3.0.0" + sdk: ^3.9.0 dependencies: - freezed_annotation: ^0.6.0 - provider: ^4.1.0-dev - todos_repository_local_storage: - path: ../todos_repository_local_storage - todos_app_core: - path: ../todos_app_core + collection: flutter: sdk: flutter - key_value_store_flutter: - key_value_store_web: + freezed_annotation: + provider: + todos_app_core: + path: ../todos_app_core + todos_repository_core: + path: ../todos_repository_core + todos_repository_local_storage: + path: ../todos_repository_local_storage shared_preferences: dev_dependencies: - freezed: ^0.6.1 build_runner: - mockito: - test: - flutter_test: - sdk: flutter - flutter_driver: - sdk: flutter integration_tests: path: ../integration_tests + integration_test: + sdk: flutter + flutter_lints: + flutter_test: + sdk: flutter + freezed: + mockito: + test: flutter: uses-material-design: true diff --git a/freezed_provider_value_notifier/test/app_state_test.dart b/freezed_provider_value_notifier/test/app_state_test.dart index ef8089b4..8ff0192a 100644 --- a/freezed_provider_value_notifier/test/app_state_test.dart +++ b/freezed_provider_value_notifier/test/app_state_test.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:freezed_provider_value_notifier/models.dart'; import 'package:freezed_provider_value_notifier/todo_list_model.dart'; import 'package:test/test.dart'; @@ -42,33 +38,37 @@ void main() { expect(model.filteredTodos, todos); }); - test('should return active todos if the VisibilityFilter is active', - () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final model = TodoList( - [todo1, todo2, todo3], - loading: false, - filter: VisibilityFilter.active, - ); - - expect(model.filteredTodos, [todo1, todo2]); - }); - - test('should return completed todos if the VisibilityFilter is completed', - () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final model = TodoList( - [todo1, todo2, todo3], - filter: VisibilityFilter.completed, - loading: false, - ); - - expect(model.filteredTodos, [todo3]); - }); + test( + 'should return active todos if the VisibilityFilter is active', + () async { + final todo1 = Todo('a'); + final todo2 = Todo('b'); + final todo3 = Todo('c', complete: true); + final model = TodoList( + [todo1, todo2, todo3], + loading: false, + filter: VisibilityFilter.active, + ); + + expect(model.filteredTodos, [todo1, todo2]); + }, + ); + + test( + 'should return completed todos if the VisibilityFilter is completed', + () async { + final todo1 = Todo('a'); + final todo2 = Todo('b'); + final todo3 = Todo('c', complete: true); + final model = TodoList( + [todo1, todo2, todo3], + filter: VisibilityFilter.completed, + loading: false, + ); + + expect(model.filteredTodos, [todo3]); + }, + ); }); group('TodoListController', () { test('should load todos from the repository', () async { @@ -77,13 +77,12 @@ void main() { final model = TodoListController(todosRepository: repository); expect(model.value.loading, isTrue); - expect(model.value.todos, []); + expect(model.value.todos, []); await Future.doWhile(() => Future.value(model.value.loading)); expect(model.value.todos, todos); expect(model.value.loading, isFalse); - }); test('should clear the completed todos', () async { final repository = MockRepository(); @@ -97,10 +96,7 @@ void main() { model.clearCompleted(); - expect( - model.value.todos, - [todo1, todo2], - ); + expect(model.value.todos, [todo1, todo2]); expect(repository.saveCount, 1); }); @@ -129,10 +125,7 @@ void main() { model.addTodo(todo); - expect( - model.value.todos, - [todo], - ); + expect(model.value.todos, [todo]); expect(repository.saveCount, 1); }); @@ -140,15 +133,14 @@ void main() { test('should remove a todo', () async { final repository = MockRepository(); final todo = Todo('A'); - final model = - TodoListController(todosRepository: repository, todos: [todo]); + final model = TodoListController( + todosRepository: repository, + todos: [todo], + ); model.removeTodoWithId(todo.id); - expect( - model.value.todos, - [], - ); + expect(model.value.todos, []); expect(repository.saveCount, 1); }); @@ -165,10 +157,7 @@ void main() { model.updateTodo(update); - expect( - model.value.todos, - [todo1, update, todo3], - ); + expect(model.value.todos, [todo1, update, todo3]); expect(repository.saveCount, 1); }); }); diff --git a/freezed_provider_value_notifier/test/home_screen_test.dart b/freezed_provider_value_notifier/test/home_screen_test.dart index bb8053d2..e7d8ab40 100644 --- a/freezed_provider_value_notifier/test/home_screen_test.dart +++ b/freezed_provider_value_notifier/test/home_screen_test.dart @@ -1,19 +1,17 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:freezed_provider_value_notifier/value_notifier_provider.dart'; import 'package:freezed_provider_value_notifier/home/home_screen.dart'; import 'package:freezed_provider_value_notifier/localization.dart'; import 'package:freezed_provider_value_notifier/models.dart'; import 'package:freezed_provider_value_notifier/todo_list_model.dart'; +import 'package:freezed_provider_value_notifier/value_notifier_provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; import 'mock_repository.dart'; /// Demonstrates how to test Widgets void main() { - group('HomeScreen', () { + group('$HomeScreen', () { final todoListFinder = find.byKey(ArchSampleKeys.todoList); final todoItem1Finder = find.byKey(ArchSampleKeys.todoItem('1')); final todoItem2Finder = find.byKey(ArchSampleKeys.todoItem('2')); @@ -83,14 +81,7 @@ void main() { } class _TestWidget extends StatelessWidget { - final Widget child; - final TodosRepository repository; - - const _TestWidget({ - Key key, - this.child, - this.repository, - }) : super(key: key); + const _TestWidget(); @override Widget build(BuildContext context) { @@ -104,7 +95,7 @@ class _TestWidget extends StatelessWidget { ProviderLocalizationsDelegate(), ArchSampleLocalizationsDelegate(), ], - home: child ?? const HomeScreen(), + home: const HomeScreen(), ), ); } @@ -119,10 +110,11 @@ final List defaultTodos = [ Matcher isChecked(bool isChecked) { return matchesSemantics( isChecked: isChecked, + hasTapAction: true, + hasFocusAction: true, hasCheckedState: true, + isFocusable: true, hasEnabledState: true, isEnabled: true, - isFocusable: true, - hasTapAction: true, ); } diff --git a/freezed_provider_value_notifier/test/mock_repository.dart b/freezed_provider_value_notifier/test/mock_repository.dart index 1b46fdf8..2112d16f 100644 --- a/freezed_provider_value_notifier/test/mock_repository.dart +++ b/freezed_provider_value_notifier/test/mock_repository.dart @@ -8,13 +8,13 @@ class MockRepository extends TodosRepository { int saveCount = 0; MockRepository([List todos = const []]) - : entities = todos.map((it) => it.toEntity()).toList(); + : entities = todos.map((it) => it.toEntity()).toList(); @override Future> loadTodos() async => entities; @override - Future saveTodos(List todos) async { + Future saveTodos(List todos) async { saveCount++; entities = todos; } diff --git a/freezed_provider_value_notifier/test_driver/integration_test.dart b/freezed_provider_value_notifier/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/freezed_provider_value_notifier/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/freezed_provider_value_notifier/test_driver/todo_app.dart b/freezed_provider_value_notifier/test_driver/todo_app.dart deleted file mode 100644 index f8b2ddb8..00000000 --- a/freezed_provider_value_notifier/test_driver/todo_app.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// This line imports the extension -import 'package:flutter_driver/driver_extension.dart'; -import 'package:freezed_provider_value_notifier/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/freezed_provider_value_notifier/test_driver/todo_app_test.dart b/freezed_provider_value_notifier/test_driver/todo_app_test.dart deleted file mode 100644 index fa00c88c..00000000 --- a/freezed_provider_value_notifier/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// _copyright 2018 _the _flutter _architecture _sample _authors. _all rights reserved. -// _use of this source code is governed by the _m_i_t license that can be found -// in the _l_i_c_e_n_s_e file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/freezed_provider_value_notifier/web/favicon.png b/freezed_provider_value_notifier/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/freezed_provider_value_notifier/web/favicon.png differ diff --git a/freezed_provider_value_notifier/web/icons/Icon-192.png b/freezed_provider_value_notifier/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/freezed_provider_value_notifier/web/icons/Icon-192.png differ diff --git a/freezed_provider_value_notifier/web/icons/Icon-512.png b/freezed_provider_value_notifier/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/freezed_provider_value_notifier/web/icons/Icon-512.png differ diff --git a/freezed_provider_value_notifier/web/icons/Icon-maskable-192.png b/freezed_provider_value_notifier/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/freezed_provider_value_notifier/web/icons/Icon-maskable-192.png differ diff --git a/freezed_provider_value_notifier/web/icons/Icon-maskable-512.png b/freezed_provider_value_notifier/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/freezed_provider_value_notifier/web/icons/Icon-maskable-512.png differ diff --git a/freezed_provider_value_notifier/web/index.html b/freezed_provider_value_notifier/web/index.html index 47bbc93b..5ca6c7dc 100644 --- a/freezed_provider_value_notifier/web/index.html +++ b/freezed_provider_value_notifier/web/index.html @@ -1,10 +1,38 @@ + + + - change_notifier_provider + + + + + + + + + + + + + freezed_provider_value_notifier + - + diff --git a/freezed_provider_value_notifier/web/manifest.json b/freezed_provider_value_notifier/web/manifest.json new file mode 100644 index 00000000..73befe34 --- /dev/null +++ b/freezed_provider_value_notifier/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "freezed_provider_value_notifier", + "short_name": "freezed_provider_value_notifier", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/freezed_provider_value_notifier/windows/.gitignore b/freezed_provider_value_notifier/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/freezed_provider_value_notifier/windows/.gitignore @@ -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/ diff --git a/freezed_provider_value_notifier/windows/CMakeLists.txt b/freezed_provider_value_notifier/windows/CMakeLists.txt new file mode 100644 index 00000000..2c32cde2 --- /dev/null +++ b/freezed_provider_value_notifier/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(freezed_provider_value_notifier 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 "freezed_provider_value_notifier") + +# 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) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_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 "$") +# 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) diff --git a/freezed_provider_value_notifier/windows/flutter/CMakeLists.txt b/freezed_provider_value_notifier/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/freezed_provider_value_notifier/windows/flutter/CMakeLists.txt @@ -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} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/freezed_provider_value_notifier/windows/flutter/generated_plugin_registrant.cc b/freezed_provider_value_notifier/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/freezed_provider_value_notifier/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/freezed_provider_value_notifier/windows/flutter/generated_plugin_registrant.h b/freezed_provider_value_notifier/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/freezed_provider_value_notifier/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/freezed_provider_value_notifier/windows/flutter/generated_plugins.cmake b/freezed_provider_value_notifier/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/freezed_provider_value_notifier/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +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 $) + 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) diff --git a/freezed_provider_value_notifier/windows/runner/CMakeLists.txt b/freezed_provider_value_notifier/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/freezed_provider_value_notifier/windows/runner/CMakeLists.txt @@ -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) diff --git a/freezed_provider_value_notifier/windows/runner/Runner.rc b/freezed_provider_value_notifier/windows/runner/Runner.rc new file mode 100644 index 00000000..8a4aafbc --- /dev/null +++ b/freezed_provider_value_notifier/windows/runner/Runner.rc @@ -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", "com.example" "\0" + VALUE "FileDescription", "freezed_provider_value_notifier" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "freezed_provider_value_notifier" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "freezed_provider_value_notifier.exe" "\0" + VALUE "ProductName", "freezed_provider_value_notifier" "\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 diff --git a/freezed_provider_value_notifier/windows/runner/flutter_window.cpp b/freezed_provider_value_notifier/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/freezed_provider_value_notifier/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#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( + 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 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); +} diff --git a/freezed_provider_value_notifier/windows/runner/flutter_window.h b/freezed_provider_value_notifier/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/freezed_provider_value_notifier/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#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_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/freezed_provider_value_notifier/windows/runner/main.cpp b/freezed_provider_value_notifier/windows/runner/main.cpp new file mode 100644 index 00000000..f3df47a2 --- /dev/null +++ b/freezed_provider_value_notifier/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 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"freezed_provider_value_notifier", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/freezed_provider_value_notifier/windows/runner/resource.h b/freezed_provider_value_notifier/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/freezed_provider_value_notifier/windows/runner/resource.h @@ -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 diff --git a/freezed_provider_value_notifier/windows/runner/resources/app_icon.ico b/freezed_provider_value_notifier/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/freezed_provider_value_notifier/windows/runner/resources/app_icon.ico differ diff --git a/freezed_provider_value_notifier/windows/runner/runner.exe.manifest b/freezed_provider_value_notifier/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/freezed_provider_value_notifier/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/freezed_provider_value_notifier/windows/runner/utils.cpp b/freezed_provider_value_notifier/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/freezed_provider_value_notifier/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +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 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::vector 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; +} diff --git a/freezed_provider_value_notifier/windows/runner/utils.h b/freezed_provider_value_notifier/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/freezed_provider_value_notifier/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// 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, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/freezed_provider_value_notifier/windows/runner/win32_window.cpp b/freezed_provider_value_notifier/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/freezed_provider_value_notifier/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#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(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( + 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(origin.x), + static_cast(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(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(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(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( + 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)); + } +} diff --git a/freezed_provider_value_notifier/windows/runner/win32_window.h b/freezed_provider_value_notifier/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/freezed_provider_value_notifier/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// 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_ diff --git a/frideos_library/.flutter-plugins-dependencies b/frideos_library/.flutter-plugins-dependencies deleted file mode 100644 index 4ded62f8..00000000 --- a/frideos_library/.flutter-plugins-dependencies +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"android":[{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":[]}],"date_created":"2020-02-10 11:24:01.218565","version":"1.14.7-pre.38"} \ No newline at end of file diff --git a/frideos_library/.gitignore b/frideos_library/.gitignore deleted file mode 100644 index 2ddde2a5..00000000 --- a/frideos_library/.gitignore +++ /dev/null @@ -1,73 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# 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 -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.packages -.pub-cache/ -.pub/ -/build/ - -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/frideos_library/.metadata b/frideos_library/.metadata deleted file mode 100644 index 1b5cec02..00000000 --- a/frideos_library/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 27321ebbad34b0a3fafe99fac037102196d655ff - channel: stable - -project_type: app diff --git a/frideos_library/README.md b/frideos_library/README.md deleted file mode 100644 index 4a3d7610..00000000 --- a/frideos_library/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# frideos_library sample - -An example Todo app created with the [frideos](https://pub.dartlang.org/packages/frideos) library. - -## Key Concepts - -- This example aims to implement the BLoC pattern in a slightly different way, trying to reduce the amount of code and complexity of the original implementation, making it a little bit easier to adopt by beginners. -- A singleton instance of the `AppState` class implementing the `AppStateModel` interface, holds the state of the app, here is where the only two BLoCs `TodosBloc` and `StatsBloc` are instantiated. -- The state of the app is provided to the widgets tree by the `AppStateProvider`, a StatefulWidget that uses an InheritedWidget to make possible for the widgets of the subtree to access the data. -- Instead of one BLoC per screen, in this sample a single BLoC, `TodosBloc`, contains the business logic of the screens that share similar needs (`HomeScreen`, `DetailScreen` and `AddEditScreen`). -- To send data from the `TodosBloc` to the `StatsBloc`, in order to calculate the number of active and completed todos, it is used the `send` method of the `ListSender` class. First, in the `TodosBloc` is created an instance of the `ListSender` class, then by its method `setReceiver`, in the `AppState` class is set a reference to the stream on the `StatsBloc` that will receive the todos list whenever the method `send` is called. In this case, there is no need for the two BLoCs to share the same source of data, or having to pass the `TodosBloc` as a parameter to the `StatsBloc` to get the todos list. - -## UI and Streams - -- As per the classic BLoC implementation, the widgets, most of which in this sample are Stateless, are automatically rebuilt whenever the streams emit a new event. -- Every time a new value is set, the `ValueBuilder` widget, which takes as a parameter an object implementing the StreamedObject interface of the library, rebuilds providing the updated data. This is just a widget that extends the `StreamBuilder` and adds some callbacks to handle the stream state and return a `Container` if no widget is passed to the `NoDataChild` parameter, in order to avoid to check for the `snapshot.hasData` property to not return a null widget, ultimately, resulting in a less and cleaner code. - -## Testing -There are no particular tricks for testing the app with this library. The sample was tested with unit tests that check for every feature of the apps, and by the integration test with flutter drive. \ No newline at end of file diff --git a/frideos_library/android/.gitignore b/frideos_library/android/.gitignore deleted file mode 100644 index bc2100d8..00000000 --- a/frideos_library/android/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java diff --git a/frideos_library/android/app/build.gradle b/frideos_library/android/app/build.gradle deleted file mode 100644 index af64cd13..00000000 --- a/frideos_library/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.frideos_library" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/frideos_library/android/app/src/debug/AndroidManifest.xml b/frideos_library/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index c2e1aefc..00000000 --- a/frideos_library/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/frideos_library/android/app/src/main/AndroidManifest.xml b/frideos_library/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index e9fb8d74..00000000 --- a/frideos_library/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - diff --git a/frideos_library/android/app/src/main/kotlin/com/example/frideos_library/MainActivity.kt b/frideos_library/android/app/src/main/kotlin/com/example/frideos_library/MainActivity.kt deleted file mode 100644 index 2be3277b..00000000 --- a/frideos_library/android/app/src/main/kotlin/com/example/frideos_library/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.frideos_library - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/frideos_library/android/app/src/main/res/drawable/launch_background.xml b/frideos_library/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/frideos_library/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/frideos_library/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/frideos_library/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index a3f285f9..00000000 Binary files a/frideos_library/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/frideos_library/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/frideos_library/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 5e6f3ac6..00000000 Binary files a/frideos_library/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/frideos_library/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/frideos_library/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 144d60be..00000000 Binary files a/frideos_library/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/frideos_library/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/frideos_library/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index deafae2d..00000000 Binary files a/frideos_library/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/frideos_library/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/frideos_library/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index d5614ac8..00000000 Binary files a/frideos_library/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/frideos_library/android/app/src/main/res/values/styles.xml b/frideos_library/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 00fa4417..00000000 --- a/frideos_library/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/frideos_library/android/app/src/profile/AndroidManifest.xml b/frideos_library/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index c2e1aefc..00000000 --- a/frideos_library/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/frideos_library/android/build.gradle b/frideos_library/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/frideos_library/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/frideos_library/android/gradle.properties b/frideos_library/android/gradle.properties deleted file mode 100644 index 38c8d454..00000000 --- a/frideos_library/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true -android.useAndroidX=true -android.enableJetifier=true diff --git a/frideos_library/android/gradle/wrapper/gradle-wrapper.properties b/frideos_library/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 296b146b..00000000 --- a/frideos_library/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/frideos_library/android/settings.gradle b/frideos_library/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/frideos_library/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/frideos_library/ios/.gitignore b/frideos_library/ios/.gitignore deleted file mode 100644 index e96ef602..00000000 --- a/frideos_library/ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/frideos_library/ios/Flutter/AppFrameworkInfo.plist b/frideos_library/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6b4c0f78..00000000 --- a/frideos_library/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/frideos_library/ios/Flutter/Debug.xcconfig b/frideos_library/ios/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba11..00000000 --- a/frideos_library/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/frideos_library/ios/Flutter/Release.xcconfig b/frideos_library/ios/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340..00000000 --- a/frideos_library/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/frideos_library/ios/Podfile b/frideos_library/ios/Podfile deleted file mode 100644 index b30a428b..00000000 --- a/frideos_library/ios/Podfile +++ /dev/null @@ -1,90 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '9.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; - end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end - end - generated_key_values -end - -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; - - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' - - # Plugin Pods - - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') - end -end - -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - -post_install do |installer| - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end - end -end diff --git a/frideos_library/ios/Runner.xcodeproj/project.pbxproj b/frideos_library/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index f675d633..00000000 --- a/frideos_library/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,518 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.frideosLibrary; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.frideosLibrary; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.frideosLibrary; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/frideos_library/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/frideos_library/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/frideos_library/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/frideos_library/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frideos_library/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140cf..00000000 --- a/frideos_library/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frideos_library/ios/Runner.xcworkspace/contents.xcworkspacedata b/frideos_library/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/frideos_library/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/frideos_library/ios/Runner/AppDelegate.swift b/frideos_library/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a..00000000 --- a/frideos_library/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d22f10b2..00000000 --- a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 980e5ad6..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index fd870289..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 75e84cd1..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 03ab8a84..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index a03431cb..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index f47613ee..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 7f2230a9..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 42315c6d..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index f9882cc0..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 45537513..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 6360ea17..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 152d5e12..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 310b0b8f..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 092b7bfe..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2f..00000000 --- a/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/frideos_library/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -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. \ No newline at end of file diff --git a/frideos_library/ios/Runner/Base.lproj/LaunchScreen.storyboard b/frideos_library/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/frideos_library/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frideos_library/ios/Runner/Base.lproj/Main.storyboard b/frideos_library/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/frideos_library/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frideos_library/ios/Runner/Info.plist b/frideos_library/ios/Runner/Info.plist deleted file mode 100644 index 36b7bfcd..00000000 --- a/frideos_library/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - frideos_library - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/frideos_library/ios/Runner/Runner-Bridging-Header.h b/frideos_library/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 7335fdf9..00000000 --- a/frideos_library/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file diff --git a/frideos_library/lib/app_state.dart b/frideos_library/lib/app_state.dart deleted file mode 100644 index 0c91154b..00000000 --- a/frideos_library/lib/app_state.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:path_provider/path_provider.dart'; - -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -import 'package:frideos/frideos.dart'; - -import 'package:frideos_library/blocs/stats_bloc.dart'; -import 'package:frideos_library/blocs/todos_bloc.dart'; -import 'package:frideos_library/models/models.dart'; - -class AppState extends AppStateModel { - static final AppState _singletonAppState = AppState._internal(); - - AppState._internal(); - - factory AppState() { - return _singletonAppState; - } - - LocalStorageRepository respository; - TodosBloc todosBloc; - StatsBloc statsBloc; - final tabController = StreamedValue(initialData: AppTab.todos); - - @override - void init() { - respository = const LocalStorageRepository( - localStorage: FileStorage( - 'frideos_library', - getApplicationDocumentsDirectory, - ), - ); - - todosBloc = TodosBloc(repository: respository); - statsBloc = StatsBloc(); - - todosBloc.todosSender.setReceiver(statsBloc.todosItems); - } - - @override - void dispose() { - todosBloc.dispose(); - statsBloc.dispose(); - tabController.dispose(); - } -} diff --git a/frideos_library/lib/blocs/stats_bloc.dart b/frideos_library/lib/blocs/stats_bloc.dart deleted file mode 100644 index d50f5f64..00000000 --- a/frideos_library/lib/blocs/stats_bloc.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:frideos/frideos.dart'; - -import 'package:frideos_library/models/models.dart'; - -class StatsBloc { - StatsBloc() { - todosItems.onChange((todos) { - numActive.value = - todos?.fold(0, (sum, todo) => !todo.complete ? ++sum : sum); - - numComplete.value = - todos?.fold(0, (sum, todo) => todo.complete ? ++sum : sum); - }); - } - // This will receive the todos from the TodoBloc. - final todosItems = StreamedList(); - - final numActive = StreamedValue(); - final numComplete = StreamedValue(); - - void dispose() { - todosItems.dispose(); - numActive.dispose(); - numComplete.dispose(); - } -} diff --git a/frideos_library/lib/blocs/todos_bloc.dart b/frideos_library/lib/blocs/todos_bloc.dart deleted file mode 100644 index 6f791446..00000000 --- a/frideos_library/lib/blocs/todos_bloc.dart +++ /dev/null @@ -1,162 +0,0 @@ -import 'package:todos_repository_core/todos_repository_core.dart'; - -import 'package:frideos/frideos.dart'; - -import 'package:frideos_library/models/models.dart'; - -class TodosBloc { - final TodosRepository repository; - - TodosBloc({this.repository}) { - _init(); - } - - void _init() async { - // Load the todos from the repository - await loadTodos(); - - // Listening for changes in the todos list, updated the streams and save - // to the repository. It is the same as: - // - // todosItems.outStream.listen((todos) => onTodosChange(...) - // - todosItems.onChange((todos) => - onTodosChange(allComplete, hasCompletedTodos, todos, onDataLoaded)); - - // Listening for changes in the VisibilityFilter and filter the visible - // todos depending on the current filter.: - activeFilter - .onChange((filter) => onFilterChange(todosItems, visibleTodos, filter)); - } - - // STREAMS - // - final todosItems = StreamedList(); - final visibleTodos = StreamedList(); - final activeFilter = - StreamedValue(initialData: VisibilityFilter.all); - final currentTodo = StreamedValue(initialData: Todo('Initializing')); - final allComplete = StreamedValue(initialData: false); - final hasCompletedTodos = StreamedValue(initialData: false); - - // SENDER (to send the todosItems list to the StatsBloc) - // - final todosSender = ListSender(); - - // METHODS - // - void loadTodos() async { - var todos = await repository.loadTodos(); - todosItems.value = todos.map(Todo.fromEntity).toList() ?? []; - todosSender.send(todosItems.value); - } - - /// Every time the todos list changes, this method will save the todos, update - /// the visible todos, and send to the statsBloc the todos list. - void onDataLoaded() { - saveTodos(); - updateVisibleItems(); - todosSender.send(todosItems.value); - } - - void updateVisibleItems() => - visibleTodos.value = filterTodos(todosItems.value, activeFilter.value); - - void saveTodos() => repository - .saveTodos(todosItems.value.map((item) => item.toEntity()).toList()); - - void addTodo(Todo todo) => todosItems.addElement(todo); - - void updateTodo(Todo todo) { - todosItems.replace(currentTodo.value, todo); - currentTodo.value = todo; - } - - void addEdit(bool isEditing, String task, String note) { - if (isEditing) { - updateTodo(currentTodo.value.copyWith(task: task, note: note)); - } else { - addTodo(Todo( - task, - note: note, - )); - } - } - - void deleteTodo(Todo todo) => todosItems.removeElement(todo); - - void onCheckboxChanged(Todo todo) { - var updatedTodo = todo.copyWith(complete: !todo.complete); - todosItems?.replace(todo, updatedTodo); - currentTodo.value = updatedTodo; - } - - void clearCompleted() { - todosItems.value.removeWhere((todo) => todo.complete); - - // Call the refresh method to update the stream when - // there is no implementation of the respective method - // on the StreamedList class, read the docs for details. - todosItems.refresh(); - } - - void toggleAll() { - var areAllComplete = todosItems.value.every((todo) => todo.complete); - todosItems.value = todosItems.value - .map((todo) => todo.copyWith(complete: !areAllComplete)) - .toList(); - } - - void extraAction(ExtraAction action) { - if (action == ExtraAction.toggleAllComplete) { - toggleAll(); - } else if (action == ExtraAction.clearCompleted) { - clearCompleted(); - } - } - - static void onTodosChange( - StreamedValue _allComplete, - StreamedValue _hasCompletedTodos, - List todos, - Function _onDataLoaded, - ) { - _allComplete.value = todos.every((todo) => todo.complete); - _hasCompletedTodos.value = todos.any((todo) => todo.complete); - - // Saving items, updating visible items and sending to the statsBloc - // the todos list. - _onDataLoaded(); - } - - static void onFilterChange(StreamedList _todosItems, - StreamedList _visibleTodos, VisibilityFilter _filter) { - if (_todosItems.value != null) { - _visibleTodos.value = filterTodos(_todosItems.value, _filter); - } - } - - static List filterTodos(List todos, VisibilityFilter filter) { - return todos.where((todo) { - switch (filter) { - case VisibilityFilter.active: - return !todo.complete; - case VisibilityFilter.completed: - return todo.complete; - case VisibilityFilter.all: - default: - return true; - } - }).toList(); - } - - /// To close all the streams - void dispose() { - todosItems.dispose(); - currentTodo.dispose(); - activeFilter.dispose(); - allComplete.dispose(); - hasCompletedTodos.dispose(); - visibleTodos.dispose(); - } -} diff --git a/frideos_library/lib/localization.dart b/frideos_library/lib/localization.dart deleted file mode 100644 index 50f117bd..00000000 --- a/frideos_library/lib/localization.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; - -class FrideosLocalizations { - static FrideosLocalizations of(BuildContext context) { - return Localizations.of( - context, FrideosLocalizations); - } - - String get appTitle => 'Frideos Example'; -} - -class FrideosLocalizationsDelegate - extends LocalizationsDelegate { - @override - Future load(Locale locale) => - Future(() => FrideosLocalizations()); - - @override - bool shouldReload(FrideosLocalizationsDelegate old) => false; - - @override - bool isSupported(Locale locale) => - locale.languageCode.toLowerCase().contains('en'); -} diff --git a/frideos_library/lib/main.dart b/frideos_library/lib/main.dart deleted file mode 100644 index 909d6f94..00000000 --- a/frideos_library/lib/main.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:frideos/frideos.dart'; -import 'package:frideos_library/app_state.dart'; -import 'package:frideos_library/localization.dart'; -import 'package:frideos_library/screens/add_edit_screen.dart'; -import 'package:frideos_library/screens/homescreen.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -void main() { - runApp(FrideosApp()); -} - -class FrideosApp extends StatelessWidget { - final appState = AppState(); - - @override - Widget build(BuildContext context) { - return AppStateProvider( - appState: appState, - child: MaterialApp( - onGenerateTitle: (context) => FrideosLocalizations.of(context).appTitle, - theme: ArchSampleTheme.theme, - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - FrideosLocalizationsDelegate(), - ], - routes: { - ArchSampleRoutes.home: (context) => HomeScreen(), - ArchSampleRoutes.addTodo: (context) => AddEditScreen(), - }, - ), - ); - } -} diff --git a/frideos_library/lib/models/extra_actions_model.dart b/frideos_library/lib/models/extra_actions_model.dart deleted file mode 100644 index d875c3cb..00000000 --- a/frideos_library/lib/models/extra_actions_model.dart +++ /dev/null @@ -1,8 +0,0 @@ -class ExtraActionsButtonViewModel { - final bool allComplete; - final bool hasCompletedTodos; - - ExtraActionsButtonViewModel(this.allComplete, this.hasCompletedTodos); -} - -enum ExtraAction { toggleAllComplete, clearCompleted } diff --git a/frideos_library/lib/models/models.dart b/frideos_library/lib/models/models.dart deleted file mode 100644 index 7767e8d0..00000000 --- a/frideos_library/lib/models/models.dart +++ /dev/null @@ -1,6 +0,0 @@ -export 'extra_actions_model.dart'; -export 'package:frideos_library/models/todo.dart'; - -enum VisibilityFilter { all, active, completed } - -enum AppTab { todos, stats } diff --git a/frideos_library/lib/models/todo.dart b/frideos_library/lib/models/todo.dart deleted file mode 100644 index 53ce9976..00000000 --- a/frideos_library/lib/models/todo.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -class Todo { - final bool complete; - final String id; - final String note; - final String task; - - Todo(this.task, {this.complete = false, String note = '', String id}) - : note = note ?? '', - id = id ?? Uuid().generateV4(); - - Todo copyWith({bool complete, String id, String note, String task}) { - return Todo( - task ?? this.task, - complete: complete ?? this.complete, - id: id ?? this.id, - note: note ?? this.note, - ); - } - - @override - int get hashCode => - complete.hashCode ^ task.hashCode ^ note.hashCode ^ id.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is Todo && - runtimeType == other.runtimeType && - complete == other.complete && - task == other.task && - note == other.note && - id == other.id; - - @override - String toString() { - return 'Todo{complete: $complete, task: $task, note: $note, id: $id}'; - } - - TodoEntity toEntity() { - return TodoEntity(task, id, note, complete); - } - - static Todo fromEntity(TodoEntity entity) { - return Todo( - entity.task, - complete: entity.complete ?? false, - note: entity.note, - id: entity.id ?? Uuid().generateV4(), - ); - } -} diff --git a/frideos_library/lib/screens/add_edit_screen.dart b/frideos_library/lib/screens/add_edit_screen.dart deleted file mode 100644 index 872a18f9..00000000 --- a/frideos_library/lib/screens/add_edit_screen.dart +++ /dev/null @@ -1,107 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:frideos/frideos.dart'; - -import 'package:frideos_library/app_state.dart'; -import 'package:frideos_library/models/models.dart'; - -class AddEditScreen extends StatefulWidget { - // Set to false by default to show the 'add todo'. - // On 'detail screen', push this screen with isEditing set - // to 'true', so that the fab will be used to edit an existing todo. - final bool isEditing; - - AddEditScreen({ - Key key, - this.isEditing = false, - }) : super(key: key ?? ArchSampleKeys.addTodoScreen); - - @override - _AddEditScreenState createState() => _AddEditScreenState(); -} - -class _AddEditScreenState extends State { - static final GlobalKey formKey = GlobalKey(); - - String _task; - String _note; - - @override - Widget build(BuildContext context) { - final bloc = AppStateProvider.of(context).todosBloc; - var isEditing = widget.isEditing; - - return ValueBuilder( - streamed: bloc.currentTodo, - builder: (context, snapshot) => Scaffold( - appBar: AppBar( - title: Text( - isEditing - ? ArchSampleLocalizations.of(context).editTodo - : ArchSampleLocalizations.of(context).addTodo, - ), - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: Form( - key: formKey, - autovalidate: false, - onWillPop: () { - return Future(() => true); - }, - child: ListView( - children: [ - TextFormField( - initialValue: isEditing ? snapshot.data.task : '', - key: ArchSampleKeys.taskField, - autofocus: isEditing ? false : true, - style: Theme.of(context).textTheme.headline, - decoration: InputDecoration( - hintText: ArchSampleLocalizations.of(context).newTodoHint, - ), - validator: (val) => val.trim().isEmpty - ? ArchSampleLocalizations.of(context).emptyTodoError - : null, - onSaved: (value) => _task = value, - ), - TextFormField( - initialValue: isEditing ? snapshot.data.note : '', - key: ArchSampleKeys.noteField, - maxLines: 10, - style: Theme.of(context).textTheme.subhead, - decoration: InputDecoration( - hintText: ArchSampleLocalizations.of(context).notesHint, - ), - onSaved: (value) => _note = value, - ) - ], - ), - ), - ), - floatingActionButton: FloatingActionButton( - key: isEditing - ? ArchSampleKeys.saveTodoFab - : ArchSampleKeys.saveNewTodo, - tooltip: isEditing - ? ArchSampleLocalizations.of(context).saveChanges - : ArchSampleLocalizations.of(context).addTodo, - child: Icon(isEditing ? Icons.check : Icons.add), - onPressed: () { - final form = formKey.currentState; - if (form.validate()) { - form.save(); - - bloc.addEdit(isEditing, _task, _note); - - Navigator.pop(context); - } - }, - ), - ), - ); - } -} diff --git a/frideos_library/lib/screens/detail_screen.dart b/frideos_library/lib/screens/detail_screen.dart deleted file mode 100644 index 3d5c7929..00000000 --- a/frideos_library/lib/screens/detail_screen.dart +++ /dev/null @@ -1,106 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:frideos/frideos.dart'; - -import 'package:frideos_library/app_state.dart'; -import 'package:frideos_library/models/models.dart'; -import 'package:frideos_library/screens/add_edit_screen.dart'; -import 'package:frideos_library/widgets/loading.dart'; - -class DetailScreen extends StatelessWidget { - DetailScreen() : super(key: ArchSampleKeys.todoDetailsScreen); - - @override - Widget build(BuildContext context) { - final bloc = AppStateProvider.of(context).todosBloc; - - return ValueBuilder( - streamed: bloc.currentTodo, - noDataChild: LoadingSpinner(key: ArchSampleKeys.todosLoading), - builder: (context, snapshot) { - final todo = snapshot.data; - - return Scaffold( - appBar: AppBar( - title: Text(ArchSampleLocalizations.of(context).todoDetails), - actions: [ - IconButton( - key: ArchSampleKeys.deleteTodoButton, - tooltip: ArchSampleLocalizations.of(context).deleteTodo, - icon: Icon(Icons.delete), - onPressed: () { - bloc.deleteTodo(todo); - Navigator.pop(context, todo); - }, - ) - ], - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: ListView( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(right: 8.0), - child: Checkbox( - value: todo.complete, - key: ArchSampleKeys.detailsTodoItemCheckbox, - onChanged: (_) => bloc.onCheckboxChanged(todo), - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), - child: Text( - todo.task, - key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, - ), - ), - Text( - todo.note, - key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) - ], - ), - ), - ], - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - tooltip: ArchSampleLocalizations.of(context).editTodo, - child: Icon(Icons.edit), - key: ArchSampleKeys.editTodoFab, - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) { - // Set the isEditing flag to true to push the page - // in 'editing mode'. - return AddEditScreen( - isEditing: true, - key: ArchSampleKeys.editTodoScreen, - ); - }, - ), - ); - }, - ), - ); - }, - ); - } -} diff --git a/frideos_library/lib/screens/homescreen.dart b/frideos_library/lib/screens/homescreen.dart deleted file mode 100644 index 5da926b9..00000000 --- a/frideos_library/lib/screens/homescreen.dart +++ /dev/null @@ -1,92 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:frideos/frideos.dart'; - -import 'package:frideos_library/app_state.dart'; -import 'package:frideos_library/localization.dart'; -import 'package:frideos_library/blocs/todos_bloc.dart'; -import 'package:frideos_library/models/models.dart'; -import 'package:frideos_library/widgets/extra_actions_button.dart'; -import 'package:frideos_library/widgets/filter_button.dart'; -import 'package:frideos_library/widgets/todo_list.dart'; -import 'package:frideos_library/widgets/stats_counter.dart'; - -class HomeScreen extends StatelessWidget { - @override - Widget build(BuildContext context) { - final bloc = AppStateProvider.of(context).todosBloc; - final tabController = AppStateProvider.of(context).tabController; - - return ValueBuilder( - streamed: tabController, - builder: (context, activeTabSnapshot) => Scaffold( - appBar: AppBar( - title: Text(FrideosLocalizations.of(context).appTitle), - actions: _buildActions( - bloc, - activeTabSnapshot, - ), - ), - body: activeTabSnapshot.data == AppTab.todos - ? TodoList() - : StatsCounter(), - floatingActionButton: FloatingActionButton( - key: ArchSampleKeys.addTodoFab, - onPressed: () { - Navigator.pushNamed(context, ArchSampleRoutes.addTodo); - }, - child: Icon(Icons.add), - tooltip: ArchSampleLocalizations.of(context).addTodo, - ), - bottomNavigationBar: BottomNavigationBar( - key: ArchSampleKeys.tabs, - currentIndex: AppTab.values.indexOf(activeTabSnapshot.data), - onTap: (index) { - tabController.value = AppTab.values[index]; - }, - items: AppTab.values.map((tab) { - return BottomNavigationBarItem( - icon: Icon( - tab == AppTab.todos ? Icons.list : Icons.show_chart, - key: tab == AppTab.stats - ? ArchSampleKeys.statsTab - : ArchSampleKeys.todoTab, - ), - title: Text( - tab == AppTab.stats - ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos, - ), - ); - }).toList(), - ), - ), - ); - } - - List _buildActions( - TodosBloc bloc, AsyncSnapshot activeTabSnapshot) { - return [ - ValueBuilder( - streamed: bloc.activeFilter, - builder: (context, snapshot) { - return FilterButton( - isActive: activeTabSnapshot.data == AppTab.todos, - activeFilter: snapshot.data ?? VisibilityFilter.all, - onSelected: bloc.activeFilter.inStream, - ); - }, - ), - ValueBuilder( - streamed: bloc.allComplete, - builder: (context, snapshot) { - return ExtraActionsButton( - allComplete: snapshot?.data ?? false, - ); - }, - ), - ]; - } -} diff --git a/frideos_library/lib/widgets/extra_actions_button.dart b/frideos_library/lib/widgets/extra_actions_button.dart deleted file mode 100644 index cdc710d7..00000000 --- a/frideos_library/lib/widgets/extra_actions_button.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:frideos/frideos.dart'; - -import 'package:frideos_library/app_state.dart'; -import 'package:frideos_library/models/models.dart'; - -class ExtraActionsButton extends StatelessWidget { - final bool allComplete; - - ExtraActionsButton({ - this.allComplete = false, - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return PopupMenuButton( - key: ArchSampleKeys.extraActionsButton, - onSelected: AppStateProvider.of(context).todosBloc.extraAction, - itemBuilder: (BuildContext context) { - return >[ - PopupMenuItem( - key: ArchSampleKeys.toggleAll, - value: ExtraAction.toggleAllComplete, - child: Text( - allComplete - ? ArchSampleLocalizations.of(context).markAllIncomplete - : ArchSampleLocalizations.of(context).markAllComplete, - ), - ), - PopupMenuItem( - key: ArchSampleKeys.clearCompleted, - value: ExtraAction.clearCompleted, - child: Text( - ArchSampleLocalizations.of(context).clearCompleted, - ), - ), - ]; - }, - ); - } -} diff --git a/frideos_library/lib/widgets/filter_button.dart b/frideos_library/lib/widgets/filter_button.dart deleted file mode 100644 index ae2f4597..00000000 --- a/frideos_library/lib/widgets/filter_button.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:frideos_library/models/models.dart'; - -class FilterButton extends StatelessWidget { - final PopupMenuItemSelected onSelected; - final VisibilityFilter activeFilter; - final bool isActive; - - FilterButton({this.onSelected, this.activeFilter, this.isActive, Key key}) - : super(key: key); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final defaultStyle = theme.textTheme.body1; - final activeStyle = theme.textTheme.body1.copyWith( - color: theme.accentColor, - ); - final button = _Button( - onSelected: onSelected, - activeFilter: activeFilter, - activeStyle: activeStyle, - defaultStyle: defaultStyle, - ); - - return AnimatedOpacity( - opacity: isActive ? 1.0 : 0.0, - duration: Duration(milliseconds: 150), - child: isActive ? button : IgnorePointer(child: button), - ); - } -} - -class _Button extends StatelessWidget { - const _Button({ - Key key, - @required this.onSelected, - @required this.activeFilter, - @required this.activeStyle, - @required this.defaultStyle, - }) : super(key: key); - - final PopupMenuItemSelected onSelected; - final VisibilityFilter activeFilter; - final TextStyle activeStyle; - final TextStyle defaultStyle; - - @override - Widget build(BuildContext context) { - return PopupMenuButton( - key: ArchSampleKeys.filterButton, - tooltip: ArchSampleLocalizations.of(context).filterTodos, - onSelected: onSelected, - itemBuilder: (BuildContext context) { - return >[ - PopupMenuItem( - key: ArchSampleKeys.allFilter, - value: VisibilityFilter.all, - child: Text( - ArchSampleLocalizations.of(context).showAll, - style: activeFilter == VisibilityFilter.all - ? activeStyle - : defaultStyle, - ), - ), - PopupMenuItem( - key: ArchSampleKeys.activeFilter, - value: VisibilityFilter.active, - child: Text( - ArchSampleLocalizations.of(context).showActive, - style: activeFilter == VisibilityFilter.active - ? activeStyle - : defaultStyle, - ), - ), - PopupMenuItem( - key: ArchSampleKeys.completedFilter, - value: VisibilityFilter.completed, - child: Text( - ArchSampleLocalizations.of(context).showCompleted, - style: activeFilter == VisibilityFilter.completed - ? activeStyle - : defaultStyle, - ), - ), - ]; - }, - icon: Icon(Icons.filter_list), - ); - } -} diff --git a/frideos_library/lib/widgets/loading.dart b/frideos_library/lib/widgets/loading.dart deleted file mode 100644 index 2cf57230..00000000 --- a/frideos_library/lib/widgets/loading.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter/material.dart'; - -class LoadingSpinner extends StatelessWidget { - LoadingSpinner({Key key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Center( - child: CircularProgressIndicator(), - ); - } -} diff --git a/frideos_library/lib/widgets/stats_counter.dart b/frideos_library/lib/widgets/stats_counter.dart deleted file mode 100644 index 6014fd4b..00000000 --- a/frideos_library/lib/widgets/stats_counter.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:frideos/frideos.dart'; - -import 'package:frideos_library/app_state.dart'; - -class StatsCounter extends StatelessWidget { - @override - Widget build(BuildContext context) { - var bloc = AppStateProvider.of(context).statsBloc; - - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: ValueBuilder( - streamed: bloc.numComplete, - builder: (context, snapshot) => Text( - '${snapshot.data ?? 0}', - key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, - ), - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: ValueBuilder( - streamed: bloc.numActive, - builder: (context, snapshot) { - return Text( - '${snapshot.data ?? 0}', - key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, - ); - }, - ), - ) - ], - ), - ); - } -} diff --git a/frideos_library/lib/widgets/todo_item.dart b/frideos_library/lib/widgets/todo_item.dart deleted file mode 100644 index 5181dc25..00000000 --- a/frideos_library/lib/widgets/todo_item.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:frideos_library/models/todo.dart'; - -class TodoItem extends StatelessWidget { - final DismissDirectionCallback onDismissed; - final GestureTapCallback onTap; - final ValueChanged onCheckboxChanged; - final Todo todo; - - TodoItem({ - @required this.onDismissed, - @required this.onTap, - @required this.onCheckboxChanged, - @required this.todo, - }); - - @override - Widget build(BuildContext context) { - return Dismissible( - key: ArchSampleKeys.todoItem(todo.id), - onDismissed: onDismissed, - child: ListTile( - onTap: onTap, - leading: Checkbox( - key: ArchSampleKeys.todoItemCheckbox(todo.id), - value: todo.complete, - onChanged: onCheckboxChanged, - ), - title: Text( - todo.task, - key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, - ), - subtitle: Text( - todo.note, - key: ArchSampleKeys.todoItemNote(todo.id), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, - ), - ), - ); - } -} diff --git a/frideos_library/lib/widgets/todo_list.dart b/frideos_library/lib/widgets/todo_list.dart deleted file mode 100644 index b09e89c1..00000000 --- a/frideos_library/lib/widgets/todo_list.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:frideos/frideos.dart'; - -import 'package:frideos_library/app_state.dart'; -import 'package:frideos_library/models/todo.dart'; -import 'package:frideos_library/screens/detail_screen.dart'; -import 'package:frideos_library/widgets/loading.dart'; -import 'package:frideos_library/widgets/todo_item.dart'; - -class TodoList extends StatelessWidget { - TodoList({Key key}) : super(key: key); - - @override - Widget build(BuildContext context) { - var bloc = AppStateProvider.of(context).todosBloc; - - return ValueBuilder>( - streamed: bloc.visibleTodos, - noDataChild: LoadingSpinner(key: ArchSampleKeys.todosLoading), - builder: (context, snapshot) => Container( - child: ListView.builder( - key: ArchSampleKeys.todoList, - itemCount: snapshot.data.length, - itemBuilder: (BuildContext context, int index) { - final todo = snapshot.data[index]; - - return TodoItem( - todo: todo, - onDismissed: (direction) { - _removeTodo(context, todo); - }, - onTap: () { - bloc.currentTodo.value = todo; - - Navigator.push( - context, - MaterialPageRoute(builder: (context) => DetailScreen()), - ).then((todo) { - if (todo is Todo) { - _showUndoSnackbar(context, todo); - } - }); - }, - onCheckboxChanged: (complete) => bloc.onCheckboxChanged(todo), - ); - }), - ), - ); - } - - void _removeTodo(BuildContext context, Todo todo) { - AppStateProvider.of(context).todosBloc.deleteTodo(todo); - _showUndoSnackbar(context, todo); - } - - void _showUndoSnackbar(BuildContext context, Todo todo) { - final snackBar = SnackBar( - key: ArchSampleKeys.snackbar, - duration: Duration(seconds: 2), - content: Text( - ArchSampleLocalizations.of(context).todoDeleted(todo.task), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - action: SnackBarAction( - key: ArchSampleKeys.snackbarAction(todo.id), - label: ArchSampleLocalizations.of(context).undo, - onPressed: () { - AppStateProvider.of(context).todosBloc.addTodo(todo); - }, - ), - ); - - Scaffold.of(context).showSnackBar(snackBar); - } -} diff --git a/frideos_library/pubspec.yaml b/frideos_library/pubspec.yaml deleted file mode 100644 index 1a4a6a51..00000000 --- a/frideos_library/pubspec.yaml +++ /dev/null @@ -1,78 +0,0 @@ -name: frideos_library -description: A new Flutter project. - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 - -environment: - sdk: ">=2.1.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - frideos: ^1.0.0+1 - todos_app_core: - path: ../todos_app_core - todos_repository_local_storage: - path: ../todos_repository_local_storage - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_driver: - sdk: flutter - test: - mockito: - integration_tests: - path: ../integration_tests - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/frideos_library/test/stats_bloc_test.dart b/frideos_library/test/stats_bloc_test.dart deleted file mode 100644 index 2fbeae2b..00000000 --- a/frideos_library/test/stats_bloc_test.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'dart:async'; - -import 'package:test/test.dart'; - -import 'package:todos_repository_core/todos_repository_core.dart'; - -import 'package:frideos_library/blocs/todos_bloc.dart'; -import 'package:frideos_library/blocs/stats_bloc.dart'; -import 'package:frideos_library/models/models.dart'; - -class MockRepository extends TodosRepository { - List entities; - - MockRepository(List todos) - : entities = todos.map((it) => it.toEntity()).toList(); - - @override - Future> loadTodos() { - return Future.value(entities); - } - - @override - Future saveTodos(List todos) { - return Future.sync(() => entities = todos); - } -} - -void main() { - group('StatsBloc', () { - test('should stream the number of active todos', () async { - final statsBloc = StatsBloc(); - - var todos = [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]; - - final todosBloc = TodosBloc(repository: MockRepository(todos)); - - todosBloc.todosSender.setReceiver(statsBloc.todosItems); - - await todosBloc.loadTodos(); - - await expectLater(statsBloc.numActive.outStream, emits(2)); - }); - - test('should stream the number of completed todos', () async { - final statsBloc = StatsBloc(); - - final todos = [ - Todo('a'), - Todo('b'), - Todo('Hallo', complete: true), - Todo('Friend', complete: true), - Todo('Flutter', complete: true), - ]; - - final todosBloc = TodosBloc(repository: MockRepository(todos)); - - todosBloc.todosSender.setReceiver(statsBloc.todosItems); - - await todosBloc.loadTodos(); - - await expectLater(statsBloc.numComplete.outStream, emits(3)); - }); - }); -} diff --git a/frideos_library/test/todos_bloc_test.dart b/frideos_library/test/todos_bloc_test.dart deleted file mode 100644 index e3179f58..00000000 --- a/frideos_library/test/todos_bloc_test.dart +++ /dev/null @@ -1,362 +0,0 @@ -import 'dart:async'; - -import 'package:test/test.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -import 'package:frideos_library/models/models.dart'; -import 'package:frideos_library/blocs/todos_bloc.dart'; - -import 'package:frideos/frideos.dart'; - -class MockRepository extends TodosRepository { - List entities; - - MockRepository(List todos) - : entities = todos.map((it) => it.toEntity()).toList(); - - @override - Future> loadTodos() { - return Future.value(entities); - } - - @override - Future saveTodos(List todos) { - return Future.sync(() => entities = todos); - } -} - -void main() { - group('TodosBloc', () { - test('Add a new todo', () async { - final todosBloc = TodosBloc( - repository: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - final todoToAdd = Todo('d'); - - todosBloc.addTodo(todoToAdd); - - expect(todosBloc.todosItems.value.contains(todoToAdd), true); - expect(todosBloc.todosItems.length, 4); - }); - - test('Delete a todo', () async { - final todosBloc = TodosBloc( - repository: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - final todoToDelete = - todosBloc.todosItems.value.firstWhere((todo) => todo.task == 'b'); - - todosBloc.deleteTodo(todoToDelete); - - expect(todosBloc.todosItems.value.contains(todoToDelete), false); - expect(todosBloc.todosItems.length, 2); - }); - - test('Update a todo', () async { - final todosBloc = TodosBloc( - repository: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - // Todo to update - todosBloc.currentTodo.value = todosBloc.todosItems.value[1]; - - // Updated todo - final todoUpdated = Todo('d'); - - todosBloc.updateTodo(todoUpdated); - expect(todosBloc.todosItems.value[1], todoUpdated); - expect(todosBloc.todosItems.value.contains(todoUpdated), true); - expect(todosBloc.currentTodo.value, todoUpdated); - expect(todosBloc.todosItems.length, 3); - }); - - test('Testing addEdit method', () async { - final todosBloc = TodosBloc( - repository: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - // Todo adding - todosBloc.addEdit(false, 'd', 'note'); - - expect(todosBloc.todosItems.value.firstWhere((todo) => todo.task == 'd'), - isNotNull); - expect(todosBloc.todosItems.length, 4); - - // Todo editing - todosBloc.currentTodo.value = - todosBloc.todosItems.value.firstWhere((todo) => todo.task == 'd'); - todosBloc.addEdit(true, 'e', 'note'); - - expect(todosBloc.todosItems.value.firstWhere((todo) => todo.task == 'e'), - isNotNull); - expect(todosBloc.todosItems.length, 4); - }); - - test('Change todo complete status', () async { - final todosBloc = TodosBloc( - repository: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - // Todo to update - final todoToUpdate = - todosBloc.todosItems.value.firstWhere((todo) => todo.task == 'c'); - - // Changing complete status - todosBloc.onCheckboxChanged(todoToUpdate); - - expect(todosBloc.todosItems.value.contains(todoToUpdate), false); - expect( - todosBloc.todosItems.value - .contains(todoToUpdate.copyWith(complete: false)), - true); - expect(todosBloc.todosItems.length, 3); - }); - - test('should check if there are completed todos', () async { - final todosBloc = TodosBloc( - repository: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - expect(todosBloc.todosItems.value.any((it) => it.complete), true); - }); - - test('should calculate the number of active todos', () async { - final todosBloc = TodosBloc( - repository: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - expect( - todosBloc.todosItems.value - .where((it) => !it.complete) - .toList() - .length, - 2); - }); - - test('should calculate the number of completed todos', () async { - final todosBloc = TodosBloc( - repository: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - expect( - todosBloc.todosItems.value.where((it) => it.complete).toList().length, - 1); - }); - - test('should return all todos if the VisibilityFilter is all', () async { - final todos = [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]; - final todosBloc = TodosBloc( - repository: MockRepository(todos), - ); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - todosBloc.activeFilter.value = VisibilityFilter.all; - - expect(todosBloc.visibleTodos.outStream, emits(todos)); - }); - - test('should return active todos if the VisibilityFilter is active', - () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final todosBloc = TodosBloc( - repository: MockRepository(todos), - ); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - todosBloc.activeFilter.value = VisibilityFilter.active; - - expect( - todosBloc.visibleTodos.outStream, - emitsThrough([ - todo1, - todo2, - ])); - }); - - test('should return completed todos if the VisibilityFilter is completed', - () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final todosBloc = TodosBloc( - repository: MockRepository(todos), - ); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - todosBloc.activeFilter.value = VisibilityFilter.completed; - - expect(todosBloc.visibleTodos.outStream, emitsThrough([todo3])); - }); - - test('should clear the completed todos', () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final todosBloc = TodosBloc( - repository: MockRepository(todos), - ); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - todosBloc.clearCompleted(); - - expect(todosBloc.todosItems.value, [ - todo1, - todo2, - ]); - }); - - test('toggle all as complete or incomplete', () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final todosBloc = TodosBloc( - repository: MockRepository(todos), - ); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - // Toggle all complete - todosBloc.toggleAll(); - expect(todosBloc.todosItems.value.every((t) => t.complete), isTrue); - - // Toggle all incomplete - todosBloc.toggleAll(); - expect(todosBloc.todosItems.value.every((t) => !t.complete), isTrue); - }); - - test('testing extraAction method', () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - - final todos = [ - todo1, - todo2, - ]; - final todosBloc = TodosBloc( - repository: MockRepository(todos), - ); - - final streamedList = StreamedList(); - todosBloc.todosSender.setReceiver(streamedList); - - await todosBloc.loadTodos(); - - todosBloc.extraAction(ExtraAction.toggleAllComplete); - expect(todosBloc.todosItems.value.every((t) => t.complete), isTrue); - - todosBloc.extraAction(ExtraAction.clearCompleted); - expect(todosBloc.todosItems.length, 0); - }); - }); -} diff --git a/frideos_library/test_driver/main_test.dart b/frideos_library/test_driver/main_test.dart deleted file mode 100644 index da7a453e..00000000 --- a/frideos_library/test_driver/main_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// This is a basic Flutter Driver test for the application. A Flutter Driver -// test is an end-to-end test that "drives" your application from another -// process or even from another computer. If you are familiar with -// Selenium/WebDriver for web, Espresso for Android or UI Automation for iOS, -// this is simply Flutter's version of that. - -import 'package:flutter_driver/flutter_driver.dart'; -import 'package:test/test.dart'; - -void main() { - group('end-to-end test', () { - FlutterDriver driver; - - setUpAll(() async { - // Connect to a running Flutter application instance. - driver = await FlutterDriver.connect(); - }); - - tearDownAll(() async { - if (driver != null) await driver.close(); - }); - - test('tap on the floating action button; verify counter', () async { - // Finds the floating action button (fab) to tap on - final fab = find.byTooltip('Increment'); - - // Wait for the floating action button to appear - await driver.waitFor(fab); - - // Tap on the fab - await driver.tap(fab); - - // Wait for text to change to the desired value - await driver.waitFor(find.text('1')); - }); - }); -} diff --git a/frideos_library/test_driver/todo_app.dart b/frideos_library/test_driver/todo_app.dart deleted file mode 100644 index ccf7ec05..00000000 --- a/frideos_library/test_driver/todo_app.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:flutter_driver/driver_extension.dart'; -import 'package:frideos_library/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/frideos_library/test_driver/todo_app_test.dart b/frideos_library/test_driver/todo_app_test.dart deleted file mode 100644 index 1c5a586c..00000000 --- a/frideos_library/test_driver/todo_app_test.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/index.html b/index.html index 93235215..f1e9d3d7 100644 --- a/index.html +++ b/index.html @@ -8,15 +8,11 @@ Flutter Architecture Samples - + - - - + + + + + + diff --git a/inherited_widget/android/app/src/main/res/values/styles.xml b/inherited_widget/android/app/src/main/res/values/styles.xml index 00fa4417..cb1ef880 100644 --- a/inherited_widget/android/app/src/main/res/values/styles.xml +++ b/inherited_widget/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ - + + diff --git a/inherited_widget/android/app/src/profile/AndroidManifest.xml b/inherited_widget/android/app/src/profile/AndroidManifest.xml index b12cba58..399f6981 100644 --- a/inherited_widget/android/app/src/profile/AndroidManifest.xml +++ b/inherited_widget/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/inherited_widget/android/build.gradle b/inherited_widget/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/inherited_widget/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/inherited_widget/android/build.gradle.kts b/inherited_widget/android/build.gradle.kts new file mode 100644 index 00000000..89176ef4 --- /dev/null +++ b/inherited_widget/android/build.gradle.kts @@ -0,0 +1,21 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/inherited_widget/android/gradle.properties b/inherited_widget/android/gradle.properties index 38c8d454..f018a618 100644 --- a/inherited_widget/android/gradle.properties +++ b/inherited_widget/android/gradle.properties @@ -1,4 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/inherited_widget/android/gradle/wrapper/gradle-wrapper.properties b/inherited_widget/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..ac3b4792 100644 --- a/inherited_widget/android/gradle/wrapper/gradle-wrapper.properties +++ b/inherited_widget/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/inherited_widget/android/settings.gradle b/inherited_widget/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/inherited_widget/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/inherited_widget/android/settings.gradle.kts b/inherited_widget/android/settings.gradle.kts new file mode 100644 index 00000000..ab39a10a --- /dev/null +++ b/inherited_widget/android/settings.gradle.kts @@ -0,0 +1,25 @@ +pluginManagement { + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.7.3" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/inherited_widget/integration_test/app_test.dart b/inherited_widget/integration_test/app_test.dart new file mode 100644 index 00000000..c0efe3af --- /dev/null +++ b/inherited_widget/integration_test/app_test.dart @@ -0,0 +1,21 @@ +import 'package:inherited_widget_sample/app.dart'; +import 'package:inherited_widget_sample/state_container.dart'; +import 'package:integration_tests/integration_tests.dart' as integration_tests; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; + +void main() { + integration_tests.run( + appBuilder: () async { + return StateContainer( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'inherited_widget_todos_test_${DateTime.now().toIso8601String()}', + await SharedPreferences.getInstance(), + ), + ), + child: const InheritedWidgetApp(), + ); + }, + ); +} diff --git a/inherited_widget/ios/.gitignore b/inherited_widget/ios/.gitignore index e96ef602..7a7f9873 100644 --- a/inherited_widget/ios/.gitignore +++ b/inherited_widget/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/inherited_widget/ios/Flutter/AppFrameworkInfo.plist b/inherited_widget/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f78..7c569640 100644 --- a/inherited_widget/ios/Flutter/AppFrameworkInfo.plist +++ b/inherited_widget/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 12.0 diff --git a/inherited_widget/ios/Flutter/Debug.xcconfig b/inherited_widget/ios/Flutter/Debug.xcconfig index e8efba11..ec97fc6f 100644 --- a/inherited_widget/ios/Flutter/Debug.xcconfig +++ b/inherited_widget/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/inherited_widget/ios/Flutter/Release.xcconfig b/inherited_widget/ios/Flutter/Release.xcconfig index 399e9340..c4855bfe 100644 --- a/inherited_widget/ios/Flutter/Release.xcconfig +++ b/inherited_widget/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/inherited_widget/ios/Podfile b/inherited_widget/ios/Podfile index b30a428b..e549ee22 100644 --- a/inherited_widget/ios/Podfile +++ b/inherited_widget/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -10,81 +10,34 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - generated_key_values + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' +flutter_ios_podfile_setup - # Plugin Pods +target 'Runner' do + use_frameworks! - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths end end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/inherited_widget/ios/Runner.xcodeproj/project.pbxproj b/inherited_widget/ios/Runner.xcodeproj/project.pbxproj index c1b070d9..743a969d 100644 --- a/inherited_widget/ios/Runner.xcodeproj/project.pbxproj +++ b/inherited_widget/ios/Runner.xcodeproj/project.pbxproj @@ -3,23 +3,29 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3348E430D7129BB18BC78B4B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE925AD22BC8A868F53BE025 /* Pods_Runner.framework */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -27,8 +33,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -38,23 +42,19 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 1E69637449B29CC0AB13D272 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 4A35D354374ABDAA8E56C08A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 722B0CDB9A6F3DED6856BA0F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - DE925AD22BC8A868F53BE025 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,32 +62,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - 3348E430D7129BB18BC78B4B /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 66C4DAC000F715814BBD3787 /* Pods */ = { + 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( - 4A35D354374ABDAA8E56C08A /* Pods-Runner.debug.xcconfig */, - 1E69637449B29CC0AB13D272 /* Pods-Runner.release.xcconfig */, - 722B0CDB9A6F3DED6856BA0F /* Pods-Runner.profile.xcconfig */, + 331C807B294A618700263BE5 /* RunnerTests.swift */, ); - name = Pods; - path = Pods; + path = RunnerTests; sourceTree = ""; }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -101,8 +93,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - 66C4DAC000F715814BBD3787 /* Pods */, - F4E297C3C4563E091C160C6A /* Frameworks */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -110,6 +101,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -121,7 +113,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -130,36 +121,36 @@ path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; - F4E297C3C4563E091C160C6A /* Frameworks */ = { - isa = PBXGroup; - children = ( - DE925AD22BC8A868F53BE025 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 8BAEDFE2B03121E235B57BBB /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 632B8B8C0062E80365A4A3D9 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -176,9 +167,14 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -186,7 +182,7 @@ }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -199,11 +195,19 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -220,57 +224,23 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 632B8B8C0062E80365A4A3D9 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 8BAEDFE2B03121E235B57BBB /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -286,6 +256,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -297,6 +275,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -319,9 +305,9 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -351,6 +337,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -359,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -375,18 +362,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = H54QW28H73; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidget; + PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidgetSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -394,11 +377,58 @@ }; name = Profile; }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidgetSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidgetSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidgetSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -428,6 +458,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -442,7 +473,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -452,9 +483,9 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -484,6 +515,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -492,11 +524,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -509,18 +542,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = H54QW28H73; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidget; + PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidgetSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -536,18 +565,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = H54QW28H73; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidget; + PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidgetSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -558,6 +583,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/inherited_widget/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/inherited_widget/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/inherited_widget/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/inherited_widget/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/inherited_widget/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/inherited_widget/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/inherited_widget/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/inherited_widget/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/inherited_widget/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/inherited_widget/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/inherited_widget/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/inherited_widget/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..e3773d42 100644 --- a/inherited_widget/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/inherited_widget/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + + + + + @@ -61,8 +73,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - - - diff --git a/inherited_widget/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/inherited_widget/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/inherited_widget/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/inherited_widget/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/inherited_widget/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/inherited_widget/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/inherited_widget/ios/Runner/AppDelegate.swift b/inherited_widget/ios/Runner/AppDelegate.swift index 70693e4a..62666446 100644 --- a/inherited_widget/ios/Runner/AppDelegate.swift +++ b/inherited_widget/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ -import UIKit import Flutter +import UIKit -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d22f10b2..d36b1fab 100644 --- a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -107,6 +107,12 @@ "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" } ], "info" : { diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 980e5ad6..7353c41e 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index fd870289..797d452e 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 75e84cd1..6ed2d933 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 03ab8a84..4cd7b009 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index a03431cb..fe730945 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index f47613ee..321773cd 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 7f2230a9..797d452e 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 42315c6d..502f463a 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index f9882cc0..0ec30343 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 45537513..0ec30343 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 6360ea17..e9f5fea2 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 152d5e12..84ac32ae 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 310b0b8f..8953cba0 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 092b7bfe..0467bf12 100644 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/inherited_widget/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/inherited_widget/ios/Runner/Info.plist b/inherited_widget/ios/Runner/Info.plist index 57286d07..07a3d197 100644 --- a/inherited_widget/ios/Runner/Info.plist +++ b/inherited_widget/ios/Runner/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Inherited Widget Sample CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -11,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - inherited_widget + inherited_widget_sample CFBundlePackageType APPL CFBundleShortVersionString @@ -39,7 +41,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/inherited_widget/ios/Runner/Runner-Bridging-Header.h b/inherited_widget/ios/Runner/Runner-Bridging-Header.h index 7335fdf9..308a2a56 100644 --- a/inherited_widget/ios/Runner/Runner-Bridging-Header.h +++ b/inherited_widget/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file +#import "GeneratedPluginRegistrant.h" diff --git a/inherited_widget/ios/RunnerTests/RunnerTests.swift b/inherited_widget/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/inherited_widget/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/inherited_widget/lib/app.dart b/inherited_widget/lib/app.dart index 6d7eb57b..739f9159 100644 --- a/inherited_widget/lib/app.dart +++ b/inherited_widget/lib/app.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:inherited_widget_sample/localization.dart'; import 'package:inherited_widget_sample/screens/add_edit_screen.dart'; @@ -9,14 +5,15 @@ import 'package:inherited_widget_sample/screens/home_screen.dart'; import 'package:todos_app_core/todos_app_core.dart'; class InheritedWidgetApp extends StatelessWidget { - const InheritedWidgetApp(); + const InheritedWidgetApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( + theme: ArchSampleTheme.lightTheme, + darkTheme: ArchSampleTheme.darkTheme, onGenerateTitle: (context) => InheritedWidgetLocalizations.of(context).appTitle, - theme: ArchSampleTheme.theme, localizationsDelegates: [ ArchSampleLocalizationsDelegate(), InheritedWidgetLocalizationsDelegate(), diff --git a/inherited_widget/lib/localization.dart b/inherited_widget/lib/localization.dart index e28c3f10..c48eee47 100644 --- a/inherited_widget/lib/localization.dart +++ b/inherited_widget/lib/localization.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; @@ -9,7 +5,9 @@ import 'package:flutter/material.dart'; class InheritedWidgetLocalizations { static InheritedWidgetLocalizations of(BuildContext context) { return Localizations.of( - context, InheritedWidgetLocalizations); + context, + InheritedWidgetLocalizations, + )!; } String get appTitle => 'InheritedWidget Example'; diff --git a/inherited_widget/lib/main.dart b/inherited_widget/lib/main.dart index 4b63c922..d5dc322c 100644 --- a/inherited_widget/lib/main.dart +++ b/inherited_widget/lib/main.dart @@ -1,24 +1,21 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:inherited_widget_sample/app.dart'; import 'package:inherited_widget_sample/state_container.dart'; -import 'package:key_value_store_flutter/key_value_store_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(StateContainer( - child: const InheritedWidgetApp(), - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'inherited_widget_todos', - FlutterKeyValueStore(await SharedPreferences.getInstance()), + runApp( + StateContainer( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'inherited_widget_todos', + await SharedPreferences.getInstance(), + ), ), + child: const InheritedWidgetApp(), ), - )); + ); } diff --git a/inherited_widget/lib/main_web.dart b/inherited_widget/lib/main_web.dart deleted file mode 100644 index edd3eab8..00000000 --- a/inherited_widget/lib/main_web.dart +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:html'; - -import 'package:flutter/material.dart'; -import 'package:inherited_widget_sample/app.dart'; -import 'package:inherited_widget_sample/state_container.dart'; -import 'package:key_value_store_web/key_value_store_web.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -void main() { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(StateContainer( - child: const InheritedWidgetApp(), - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'inherited_widget_todos', - WebKeyValueStore(window.localStorage), - ), - ), - )); -} diff --git a/inherited_widget/lib/models.dart b/inherited_widget/lib/models.dart index 3fedbd05..e2fd49c4 100644 --- a/inherited_widget/lib/models.dart +++ b/inherited_widget/lib/models.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -20,17 +16,15 @@ class AppState { bool get allComplete => todos.every((todo) => todo.complete); - List get filteredTodos => todos.where((todo) { - switch (activeFilter) { - case VisibilityFilter.active: - return !todo.complete; - case VisibilityFilter.completed: - return todo.complete; - case VisibilityFilter.all: - default: - return true; - } - }).toList(); + List get filteredTodos => todos + .where((todo) { + return switch (activeFilter) { + VisibilityFilter.active => !todo.complete, + VisibilityFilter.completed => todo.complete, + VisibilityFilter.all => true, + }; + }) + .toList(growable: false); bool get hasCompletedTodos => todos.any((todo) => todo.complete); @@ -58,7 +52,9 @@ class AppState { void toggleAll() { final allCurrentlyComplete = allComplete; - todos.forEach((todo) => todo.complete = !allCurrentlyComplete); + for (var todo in todos) { + todo.complete = !allCurrentlyComplete; + } } @override @@ -77,8 +73,8 @@ class Todo { String note; String task; - Todo(this.task, {this.complete = false, this.note = '', String id}) - : id = id ?? Uuid().generateV4(); + Todo(this.task, {this.complete = false, this.note = '', String? id}) + : id = id ?? Uuid().generateV4(); @override int get hashCode => @@ -106,9 +102,9 @@ class Todo { static Todo fromEntity(TodoEntity entity) { return Todo( entity.task, - complete: entity.complete ?? false, + complete: entity.complete, note: entity.note, - id: entity.id ?? Uuid().generateV4(), + id: entity.id, ); } } diff --git a/inherited_widget/lib/screens/add_edit_screen.dart b/inherited_widget/lib/screens/add_edit_screen.dart index 2fe51e63..d9f8b1b1 100644 --- a/inherited_widget/lib/screens/add_edit_screen.dart +++ b/inherited_widget/lib/screens/add_edit_screen.dart @@ -1,30 +1,22 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:inherited_widget_sample/models.dart'; import 'package:inherited_widget_sample/state_container.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class AddEditScreen extends StatefulWidget { - final Todo todo; + final Todo? todo; + + const AddEditScreen({super.key = ArchSampleKeys.addTodoScreen, this.todo}); - AddEditScreen({ - Key key, - this.todo, - }) : super(key: key ?? ArchSampleKeys.addTodoScreen); @override - _AddEditScreenState createState() => _AddEditScreenState(); + State createState() => _AddEditScreenState(); } class _AddEditScreenState extends State { static final GlobalKey _formKey = GlobalKey(); - String _task; - String _note; + String? _task; + String? _note; @override Widget build(BuildContext context) { @@ -34,65 +26,57 @@ class _AddEditScreenState extends State { return Scaffold( appBar: AppBar( - title: Text( - isEditing ? localizations.editTodo : localizations.addTodo, - ), + title: Text(isEditing ? localizations.editTodo : localizations.addTodo), ), body: Padding( padding: EdgeInsets.all(16.0), child: Form( key: _formKey, - autovalidate: false, - onWillPop: () { - return Future(() => true); - }, + autovalidateMode: AutovalidateMode.disabled, + canPop: true, child: ListView( children: [ TextFormField( - initialValue: isEditing ? widget.todo.task : '', + initialValue: isEditing ? widget.todo!.task : '', key: ArchSampleKeys.taskField, autofocus: !isEditing, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.titleLarge, decoration: InputDecoration( hintText: localizations.newTodoHint, ), validator: (val) { - return val.trim().isEmpty + return val == null || val.trim().isEmpty ? localizations.emptyTodoError : null; }, onSaved: (value) => _task = value, ), TextFormField( - initialValue: isEditing ? widget.todo.note : '', + initialValue: isEditing ? widget.todo?.note : '', key: ArchSampleKeys.noteField, maxLines: 10, - style: textTheme.subhead, - decoration: InputDecoration( - hintText: localizations.notesHint, - ), + style: textTheme.bodyMedium, + decoration: InputDecoration(hintText: localizations.notesHint), onSaved: (value) => _note = value, - ) + ), ], ), ), ), floatingActionButton: FloatingActionButton( - key: - isEditing ? ArchSampleKeys.saveTodoFab : ArchSampleKeys.saveNewTodo, + key: isEditing + ? ArchSampleKeys.saveTodoFab + : ArchSampleKeys.saveNewTodo, tooltip: isEditing ? localizations.saveChanges : localizations.addTodo, child: Icon(isEditing ? Icons.check : Icons.add), onPressed: () { - if (_formKey.currentState.validate()) { - _formKey.currentState.save(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); if (isEditing) { - container.updateTodo(widget.todo, task: _task, note: _note); + container.updateTodo(widget.todo!, task: _task!, note: _note!); } else { - container.addTodo(Todo( - _task, - note: _note, - )); + container.addTodo(Todo(_task!, note: _note!)); } Navigator.pop(context); diff --git a/inherited_widget/lib/screens/detail_screen.dart b/inherited_widget/lib/screens/detail_screen.dart index 9f05db5a..1bf0c538 100644 --- a/inherited_widget/lib/screens/detail_screen.dart +++ b/inherited_widget/lib/screens/detail_screen.dart @@ -1,20 +1,18 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:inherited_widget_sample/models.dart'; import 'package:inherited_widget_sample/screens/add_edit_screen.dart'; import 'package:inherited_widget_sample/state_container.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class DetailScreen extends StatelessWidget { final Todo todo; + final VoidCallback onDelete; - DetailScreen({ - @required this.todo, - }) : super(key: ArchSampleKeys.todoDetailsScreen); + const DetailScreen({ + super.key = ArchSampleKeys.todoDetailsScreen, + required this.todo, + required this.onDelete, + }); @override Widget build(BuildContext context) { @@ -29,10 +27,11 @@ class DetailScreen extends StatelessWidget { tooltip: ArchSampleLocalizations.of(context).deleteTodo, icon: Icon(Icons.delete), onPressed: () { - container.removeTodo(todo); - Navigator.pop(context, todo); + onDelete(); + + Navigator.pop(context); }, - ) + ), ], ), body: Padding( @@ -57,21 +56,18 @@ class DetailScreen extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), + padding: EdgeInsets.only(top: 5.0, bottom: 16.0), child: Text( todo.task, key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.titleLarge, ), ), Text( todo.note, key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) + style: Theme.of(context).textTheme.bodyMedium, + ), ], ), ), @@ -82,10 +78,9 @@ class DetailScreen extends StatelessWidget { ), floatingActionButton: FloatingActionButton( tooltip: ArchSampleLocalizations.of(context).editTodo, - child: Icon(Icons.edit), key: ArchSampleKeys.editTodoFab, onPressed: () { - Navigator.of(context).push( + Navigator.of(context).push( MaterialPageRoute( builder: (context) { return AddEditScreen( @@ -96,6 +91,7 @@ class DetailScreen extends StatelessWidget { ), ); }, + child: Icon(Icons.edit), ), ); } diff --git a/inherited_widget/lib/screens/home_screen.dart b/inherited_widget/lib/screens/home_screen.dart index ab19a8ba..4ec27865 100644 --- a/inherited_widget/lib/screens/home_screen.dart +++ b/inherited_widget/lib/screens/home_screen.dart @@ -1,9 +1,4 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:inherited_widget_sample/localization.dart'; import 'package:inherited_widget_sample/models.dart'; import 'package:inherited_widget_sample/state_container.dart'; @@ -11,9 +6,10 @@ import 'package:inherited_widget_sample/widgets/extra_actions_button.dart'; import 'package:inherited_widget_sample/widgets/filter_button.dart'; import 'package:inherited_widget_sample/widgets/stats_counter.dart'; import 'package:inherited_widget_sample/widgets/todo_list.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class HomeScreen extends StatefulWidget { - HomeScreen() : super(key: ArchSampleKeys.homeScreen); + const HomeScreen({super.key = ArchSampleKeys.homeScreen}); @override State createState() { @@ -48,7 +44,7 @@ class HomeScreenState extends State { container.clearCompleted(); } }, - ) + ), ], ), body: activeTab == AppTab.todos ? TodoList() : StatsCounter(), @@ -57,8 +53,8 @@ class HomeScreenState extends State { onPressed: () { Navigator.pushNamed(context, ArchSampleRoutes.addTodo); }, - child: Icon(Icons.add), tooltip: ArchSampleLocalizations.of(context).addTodo, + child: Icon(Icons.add), ), bottomNavigationBar: BottomNavigationBar( key: ArchSampleKeys.tabs, @@ -74,11 +70,9 @@ class HomeScreenState extends State { ? ArchSampleKeys.statsTab : ArchSampleKeys.todoTab, ), - title: Text( - tab == AppTab.stats - ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos, - ), + label: tab == AppTab.stats + ? ArchSampleLocalizations.of(context).stats + : ArchSampleLocalizations.of(context).todos, ); }).toList(), ), diff --git a/inherited_widget/lib/state_container.dart b/inherited_widget/lib/state_container.dart index 77d7a51e..6041ea81 100644 --- a/inherited_widget/lib/state_container.dart +++ b/inherited_widget/lib/state_container.dart @@ -1,26 +1,22 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:inherited_widget_sample/models.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; class StateContainer extends StatefulWidget { - final AppState state; - final TodosRepository repository; + final AppState? state; + final TodosRepository? repository; final Widget child; - StateContainer({ - @required this.child, + const StateContainer({ + super.key, + required this.child, this.repository, this.state, }); static StateContainerState of(BuildContext context) { return context - .dependOnInheritedWidgetOfExactType<_InheritedStateContainer>() + .dependOnInheritedWidgetOfExactType<_InheritedStateContainer>()! .data; } @@ -31,27 +27,28 @@ class StateContainer extends StatefulWidget { } class StateContainerState extends State { - AppState state; + late AppState state; @override void initState() { if (widget.state != null) { - state = widget.state; + state = widget.state!; } else { state = AppState.loading(); } - widget.repository.loadTodos().then((loadedTodos) { - setState(() { - state = AppState( - todos: loadedTodos.map(Todo.fromEntity).toList(), - ); - }); - }).catchError((err) { - setState(() { - state.isLoading = false; - }); - }); + widget.repository + ?.loadTodos() + .then((loadedTodos) { + setState(() { + state = AppState(todos: loadedTodos.map(Todo.fromEntity).toList()); + }); + }) + .catchError((err) { + setState(() { + state.isLoading = false; + }); + }); super.initState(); } @@ -88,10 +85,10 @@ class StateContainerState extends State { void updateTodo( Todo todo, { - bool complete, - String id, - String note, - String task, + bool? complete, + String? id, + String? note, + String? task, }) { setState(() { todo.complete = complete ?? todo.complete; @@ -105,27 +102,21 @@ class StateContainerState extends State { void setState(VoidCallback fn) { super.setState(fn); - widget.repository - .saveTodos(state.todos.map((todo) => todo.toEntity()).toList()); + widget.repository?.saveTodos( + state.todos.map((todo) => todo.toEntity()).toList(), + ); } @override Widget build(BuildContext context) { - return _InheritedStateContainer( - data: this, - child: widget.child, - ); + return _InheritedStateContainer(data: this, child: widget.child); } } class _InheritedStateContainer extends InheritedWidget { final StateContainerState data; - _InheritedStateContainer({ - Key key, - @required this.data, - @required Widget child, - }) : super(key: key, child: child); + const _InheritedStateContainer({required this.data, required super.child}); // Note: we could get fancy here and compare whether the old AppState is // different than the current AppState. However, since we know this is the @@ -135,10 +126,11 @@ class _InheritedStateContainer extends InheritedWidget { bool updateShouldNotify(_InheritedStateContainer old) => true; } -typedef TodoUpdater = void Function( - Todo todo, { - bool complete, - String id, - String note, - String task, -}); +typedef TodoUpdater = + void Function( + Todo todo, { + bool complete, + String id, + String note, + String task, + }); diff --git a/inherited_widget/lib/widgets/extra_actions_button.dart b/inherited_widget/lib/widgets/extra_actions_button.dart index cc95e3c8..e1f6eda2 100644 --- a/inherited_widget/lib/widgets/extra_actions_button.dart +++ b/inherited_widget/lib/widgets/extra_actions_button.dart @@ -1,22 +1,18 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:inherited_widget_sample/models.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class ExtraActionsButton extends StatelessWidget { - final PopupMenuItemSelected onSelected; + final PopupMenuItemSelected? onSelected; final bool allComplete; final bool hasCompletedTodos; - ExtraActionsButton({ + const ExtraActionsButton({ + super.key, this.onSelected, this.allComplete = false, this.hasCompletedTodos = true, - Key key, - }) : super(key: key); + }); @override Widget build(BuildContext context) { @@ -37,9 +33,7 @@ class ExtraActionsButton extends StatelessWidget { PopupMenuItem( key: ArchSampleKeys.clearCompleted, value: ExtraAction.clearCompleted, - child: Text( - ArchSampleLocalizations.of(context).clearCompleted, - ), + child: Text(ArchSampleLocalizations.of(context).clearCompleted), ), ]; }, diff --git a/inherited_widget/lib/widgets/filter_button.dart b/inherited_widget/lib/widgets/filter_button.dart index c6fc9bcc..d5e52e2b 100644 --- a/inherited_widget/lib/widgets/filter_button.dart +++ b/inherited_widget/lib/widgets/filter_button.dart @@ -1,25 +1,25 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:inherited_widget_sample/models.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class FilterButton extends StatelessWidget { final PopupMenuItemSelected onSelected; final VisibilityFilter activeFilter; final bool isActive; - FilterButton({this.onSelected, this.activeFilter, this.isActive, Key key}) - : super(key: key); + const FilterButton({ + super.key, + required this.onSelected, + required this.activeFilter, + required this.isActive, + }); @override Widget build(BuildContext context) { final theme = Theme.of(context); - final defaultStyle = theme.textTheme.body1; - final activeStyle = theme.textTheme.body1.copyWith( - color: theme.accentColor, + final defaultStyle = theme.textTheme.bodyMedium; + final activeStyle = theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.primary, ); final button = _Button( onSelected: onSelected, @@ -37,17 +37,16 @@ class FilterButton extends StatelessWidget { class _Button extends StatelessWidget { const _Button({ - Key key, - @required this.onSelected, - @required this.activeFilter, - @required this.activeStyle, - @required this.defaultStyle, - }) : super(key: key); + required this.onSelected, + required this.activeFilter, + required this.activeStyle, + required this.defaultStyle, + }); - final PopupMenuItemSelected onSelected; - final VisibilityFilter activeFilter; - final TextStyle activeStyle; - final TextStyle defaultStyle; + final PopupMenuItemSelected? onSelected; + final VisibilityFilter? activeFilter; + final TextStyle? activeStyle; + final TextStyle? defaultStyle; @override Widget build(BuildContext context) { diff --git a/inherited_widget/lib/widgets/stats_counter.dart b/inherited_widget/lib/widgets/stats_counter.dart index b73add39..36177d7c 100644 --- a/inherited_widget/lib/widgets/stats_counter.dart +++ b/inherited_widget/lib/widgets/stats_counter.dart @@ -1,14 +1,9 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:inherited_widget_sample/state_container.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class StatsCounter extends StatelessWidget { - StatsCounter() : super(key: ArchSampleKeys.statsCounter); + const StatsCounter({super.key = ArchSampleKeys.statsCounter}); @override Widget build(BuildContext context) { @@ -24,7 +19,7 @@ class StatsCounter extends StatelessWidget { padding: EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -32,14 +27,14 @@ class StatsCounter extends StatelessWidget { child: Text( '$numCompleted', key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), Padding( padding: EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -47,9 +42,9 @@ class StatsCounter extends StatelessWidget { child: Text( '$numActive', key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), - ) + ), ], ), ); diff --git a/inherited_widget/lib/widgets/todo_item.dart b/inherited_widget/lib/widgets/todo_item.dart index 7e071c9c..e757b514 100644 --- a/inherited_widget/lib/widgets/todo_item.dart +++ b/inherited_widget/lib/widgets/todo_item.dart @@ -1,23 +1,19 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:inherited_widget_sample/models.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class TodoItem extends StatelessWidget { final DismissDirectionCallback onDismissed; final GestureTapCallback onTap; - final ValueChanged onCheckboxChanged; + final ValueChanged onCheckboxChanged; final Todo todo; - TodoItem({ - @required this.onDismissed, - @required this.onTap, - @required this.onCheckboxChanged, - @required this.todo, + const TodoItem({ + super.key, + required this.onDismissed, + required this.onTap, + required this.onCheckboxChanged, + required this.todo, }); @override @@ -35,14 +31,14 @@ class TodoItem extends StatelessWidget { title: Text( todo.task, key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleMedium, ), subtitle: Text( todo.note, key: ArchSampleKeys.todoItemNote(todo.id), maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.bodyMedium, ), ), ); diff --git a/inherited_widget/lib/widgets/todo_list.dart b/inherited_widget/lib/widgets/todo_list.dart index 6d6075be..f45f2b94 100644 --- a/inherited_widget/lib/widgets/todo_list.dart +++ b/inherited_widget/lib/widgets/todo_list.dart @@ -1,16 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:inherited_widget_sample/models.dart'; import 'package:inherited_widget_sample/screens/detail_screen.dart'; import 'package:inherited_widget_sample/state_container.dart'; import 'package:inherited_widget_sample/widgets/todo_item.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class TodoList extends StatelessWidget { - TodoList({Key key}) : super(key: key); + const TodoList({super.key}); @override Widget build(BuildContext context) { @@ -23,9 +19,7 @@ class TodoList extends StatelessWidget { Center get _buildLoading { return Center( - child: CircularProgressIndicator( - key: ArchSampleKeys.todosLoading, - ), + child: CircularProgressIndicator(key: ArchSampleKeys.todosLoading), ); } @@ -44,19 +38,18 @@ class TodoList extends StatelessWidget { _removeTodo(context, todo); }, onTap: () { - Navigator.of(context).push( + Navigator.of(context).push( MaterialPageRoute( builder: (_) { return DetailScreen( todo: todo, + onDelete: () { + _removeTodo(context, todo); + }, ); }, ), - ).then((todo) { - if (todo is Todo) { - _showUndoSnackbar(context, todo); - } - }); + ); }, onCheckboxChanged: (complete) { container.updateTodo(todo, complete: !todo.complete); @@ -90,6 +83,6 @@ class TodoList extends StatelessWidget { ), ); - Scaffold.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(context).showSnackBar(snackBar); } } diff --git a/inherited_widget/linux/.gitignore b/inherited_widget/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/inherited_widget/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/inherited_widget/linux/CMakeLists.txt b/inherited_widget/linux/CMakeLists.txt new file mode 100644 index 00000000..f1320114 --- /dev/null +++ b/inherited_widget/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +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 "inherited_widget_sample") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.inherited_widget_sample") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +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() + +# 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() + +# 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_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# 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 +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# 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() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +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) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/inherited_widget/linux/flutter/CMakeLists.txt b/inherited_widget/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/inherited_widget/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +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. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# 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/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter 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. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/inherited_widget/linux/flutter/generated_plugin_registrant.cc b/inherited_widget/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e71a16d2 --- /dev/null +++ b/inherited_widget/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/inherited_widget/linux/flutter/generated_plugin_registrant.h b/inherited_widget/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/inherited_widget/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/inherited_widget/linux/flutter/generated_plugins.cmake b/inherited_widget/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/inherited_widget/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + 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}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/inherited_widget/linux/runner/CMakeLists.txt b/inherited_widget/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/inherited_widget/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "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 +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/inherited_widget/linux/runner/main.cc b/inherited_widget/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/inherited_widget/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/inherited_widget/linux/runner/my_application.cc b/inherited_widget/linux/runner/my_application.cc new file mode 100644 index 00000000..5d42fa96 --- /dev/null +++ b/inherited_widget/linux/runner/my_application.cc @@ -0,0 +1,130 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // 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 + // desktop). + // 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. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "inherited_widget_sample"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "inherited_widget_sample"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/inherited_widget/linux/runner/my_application.h b/inherited_widget/linux/runner/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/inherited_widget/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/inherited_widget/macos/.gitignore b/inherited_widget/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/inherited_widget/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/inherited_widget/macos/Flutter/Flutter-Debug.xcconfig b/inherited_widget/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/inherited_widget/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/inherited_widget/macos/Flutter/Flutter-Release.xcconfig b/inherited_widget/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/inherited_widget/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/inherited_widget/macos/Flutter/GeneratedPluginRegistrant.swift b/inherited_widget/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b8e2b22f --- /dev/null +++ b/inherited_widget/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/inherited_widget/macos/Podfile b/inherited_widget/macos/Podfile new file mode 100644 index 00000000..29c8eb32 --- /dev/null +++ b/inherited_widget/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/inherited_widget/macos/Podfile.lock b/inherited_widget/macos/Podfile.lock new file mode 100644 index 00000000..390b5331 --- /dev/null +++ b/inherited_widget/macos/Podfile.lock @@ -0,0 +1,30 @@ +PODS: + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + +SPEC CHECKSUMS: + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + +PODFILE CHECKSUM: 7eb978b976557c8c1cd717d8185ec483fd090a82 + +COCOAPODS: 1.16.2 diff --git a/inherited_widget/macos/Runner.xcodeproj/project.pbxproj b/inherited_widget/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..8f8bbdb7 --- /dev/null +++ b/inherited_widget/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 883B1972DDFE332C5D0B8C24 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA2DE18BD70AE05550582356 /* Pods_RunnerTests.framework */; }; + EE111C72514C26D06F01A8E0 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C06C5B30A251961A74B4818 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 03EA09412A798045C17E451D /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 292A9E225992EBE76F5DF6FC /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* inherited_widget_sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = inherited_widget_sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 3E0E486BD0E42092610A70D2 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 4C06C5B30A251961A74B4818 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + AA2DE18BD70AE05550582356 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + AB2D3888C23B6EE928C5FAD0 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + BDED5AFB76879EC2D3058B88 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + FF2D48F9FD69A5986A914DDE /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 883B1972DDFE332C5D0B8C24 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EE111C72514C26D06F01A8E0 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 65E07816A42E78C7B4DF7039 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* inherited_widget_sample.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 65E07816A42E78C7B4DF7039 /* Pods */ = { + isa = PBXGroup; + children = ( + BDED5AFB76879EC2D3058B88 /* Pods-Runner.debug.xcconfig */, + FF2D48F9FD69A5986A914DDE /* Pods-Runner.release.xcconfig */, + 292A9E225992EBE76F5DF6FC /* Pods-Runner.profile.xcconfig */, + 03EA09412A798045C17E451D /* Pods-RunnerTests.debug.xcconfig */, + 3E0E486BD0E42092610A70D2 /* Pods-RunnerTests.release.xcconfig */, + AB2D3888C23B6EE928C5FAD0 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4C06C5B30A251961A74B4818 /* Pods_Runner.framework */, + AA2DE18BD70AE05550582356 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 0A301979200D09C918D1B870 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + E96EB500C3D71F703B896061 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 4D478DB628A1396F22E0E7BE /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* inherited_widget_sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 0A301979200D09C918D1B870 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 4D478DB628A1396F22E0E7BE /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + E96EB500C3D71F703B896061 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 03EA09412A798045C17E451D /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidgetSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/inherited_widget_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/inherited_widget_sample"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3E0E486BD0E42092610A70D2 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidgetSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/inherited_widget_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/inherited_widget_sample"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AB2D3888C23B6EE928C5FAD0 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidgetSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/inherited_widget_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/inherited_widget_sample"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/inherited_widget/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/inherited_widget/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/inherited_widget/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/inherited_widget/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/inherited_widget/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..8081f450 --- /dev/null +++ b/inherited_widget/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inherited_widget/macos/Runner.xcworkspace/contents.xcworkspacedata b/inherited_widget/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/inherited_widget/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/inherited_widget/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/inherited_widget/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/inherited_widget/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/inherited_widget/macos/Runner/AppDelegate.swift b/inherited_widget/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/inherited_widget/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/inherited_widget/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/inherited_widget/macos/Runner/Base.lproj/MainMenu.xib b/inherited_widget/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/inherited_widget/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inherited_widget/macos/Runner/Configs/AppInfo.xcconfig b/inherited_widget/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..5287b745 --- /dev/null +++ b/inherited_widget/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// 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 +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = inherited_widget_sample + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.inheritedWidgetSample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/inherited_widget/macos/Runner/Configs/Debug.xcconfig b/inherited_widget/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/inherited_widget/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/inherited_widget/macos/Runner/Configs/Release.xcconfig b/inherited_widget/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/inherited_widget/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/inherited_widget/macos/Runner/Configs/Warnings.xcconfig b/inherited_widget/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/inherited_widget/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/inherited_widget/macos/Runner/DebugProfile.entitlements b/inherited_widget/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/inherited_widget/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/inherited_widget/macos/Runner/Info.plist b/inherited_widget/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/inherited_widget/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/inherited_widget/macos/Runner/MainFlutterWindow.swift b/inherited_widget/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/inherited_widget/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/inherited_widget/macos/Runner/Release.entitlements b/inherited_widget/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/inherited_widget/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/inherited_widget/macos/RunnerTests/RunnerTests.swift b/inherited_widget/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/inherited_widget/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/inherited_widget/pubspec.yaml b/inherited_widget/pubspec.yaml index 4a5f5a44..749b1c7e 100644 --- a/inherited_widget/pubspec.yaml +++ b/inherited_widget/pubspec.yaml @@ -1,5 +1,8 @@ name: inherited_widget_sample description: A new Flutter project. +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -8,29 +11,38 @@ description: A new Flutter project. # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. version: 1.0.0+1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ^3.8.1 +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter - todos_repository_local_storage: - path: ../todos_repository_local_storage todos_app_core: path: ../todos_app_core - key_value_store_flutter: - key_value_store_web: + todos_repository_core: + path: ../todos_repository_core + todos_repository_local_storage: + path: ../todos_repository_local_storage shared_preferences: dev_dependencies: + flutter_lints: flutter_test: sdk: flutter - flutter_driver: + integration_test: sdk: flutter test: mockito: diff --git a/inherited_widget/test/app_state_test.dart b/inherited_widget/test/app_state_test.dart index ba99318c..69f2a6bf 100644 --- a/inherited_widget/test/app_state_test.dart +++ b/inherited_widget/test/app_state_test.dart @@ -1,48 +1,34 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:inherited_widget_sample/models.dart'; import 'package:test/test.dart'; void main() { group('AppState', () { test('should check if there are completed todos', () { - final state = AppState(todos: [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]); + final state = AppState( + todos: [Todo('a'), Todo('b'), Todo('c', complete: true)], + ); expect(state.hasCompletedTodos, true); }); test('should calculate the number of active todos', () { - final state = AppState(todos: [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]); + final state = AppState( + todos: [Todo('a'), Todo('b'), Todo('c', complete: true)], + ); expect(state.numActive, 2); }); test('should calculate the number of completed todos', () { - final state = AppState(todos: [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]); + final state = AppState( + todos: [Todo('a'), Todo('b'), Todo('c', complete: true)], + ); expect(state.numCompleted, 1); }); test('should return all todos if the VisibilityFilter is all', () { - final todos = [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]; + final todos = [Todo('a'), Todo('b'), Todo('c', complete: true)]; final state = AppState(todos: todos, activeFilter: VisibilityFilter.all); expect(state.filteredTodos, todos); @@ -52,73 +38,49 @@ void main() { final todo1 = Todo('a'); final todo2 = Todo('b'); final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; + final todos = [todo1, todo2, todo3]; final state = AppState( todos: todos, activeFilter: VisibilityFilter.active, ); - expect(state.filteredTodos, [ - todo1, - todo2, - ]); + expect(state.filteredTodos, [todo1, todo2]); }); - test('should return completed todos if the VisibilityFilter is completed', - () { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final state = AppState( - todos: todos, - activeFilter: VisibilityFilter.completed, - ); - - expect(state.filteredTodos, [todo3]); - }); + test( + 'should return completed todos if the VisibilityFilter is completed', + () { + final todo1 = Todo('a'); + final todo2 = Todo('b'); + final todo3 = Todo('c', complete: true); + final todos = [todo1, todo2, todo3]; + final state = AppState( + todos: todos, + activeFilter: VisibilityFilter.completed, + ); + + expect(state.filteredTodos, [todo3]); + }, + ); test('should clear the completed todos', () { final todo1 = Todo('a'); final todo2 = Todo('b'); final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final state = AppState( - todos: todos, - ); + final todos = [todo1, todo2, todo3]; + final state = AppState(todos: todos); state.clearCompleted(); - expect(state.todos, [ - todo1, - todo2, - ]); + expect(state.todos, [todo1, todo2]); }); test('toggle all as complete or incomplete', () { final todo1 = Todo('a'); final todo2 = Todo('b'); final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final state = AppState( - todos: todos, - ); + final todos = [todo1, todo2, todo3]; + final state = AppState(todos: todos); // Toggle all complete state.toggleAll(); diff --git a/inherited_widget/test_driver/integration_test.dart b/inherited_widget/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/inherited_widget/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/inherited_widget/test_driver/todo_app.dart b/inherited_widget/test_driver/todo_app.dart deleted file mode 100644 index 4e1c0af8..00000000 --- a/inherited_widget/test_driver/todo_app.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// This line imports the extension -import 'package:flutter_driver/driver_extension.dart'; -import 'package:inherited_widget_sample/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/inherited_widget/test_driver/todo_app_test.dart b/inherited_widget/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/inherited_widget/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/inherited_widget/web/favicon.png b/inherited_widget/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/inherited_widget/web/favicon.png differ diff --git a/inherited_widget/web/icons/Icon-192.png b/inherited_widget/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/inherited_widget/web/icons/Icon-192.png differ diff --git a/inherited_widget/web/icons/Icon-512.png b/inherited_widget/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/inherited_widget/web/icons/Icon-512.png differ diff --git a/inherited_widget/web/icons/Icon-maskable-192.png b/inherited_widget/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/inherited_widget/web/icons/Icon-maskable-192.png differ diff --git a/inherited_widget/web/icons/Icon-maskable-512.png b/inherited_widget/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/inherited_widget/web/icons/Icon-maskable-512.png differ diff --git a/inherited_widget/web/index.html b/inherited_widget/web/index.html index 6424b68b..a5971eaf 100644 --- a/inherited_widget/web/index.html +++ b/inherited_widget/web/index.html @@ -1,10 +1,38 @@ + + + - inherited_widget + + + + + + + + + + + + + inherited_widget_sample + - + diff --git a/inherited_widget/web/manifest.json b/inherited_widget/web/manifest.json new file mode 100644 index 00000000..6a86777a --- /dev/null +++ b/inherited_widget/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "inherited_widget_sample", + "short_name": "inherited_widget_sample", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/inherited_widget/windows/.gitignore b/inherited_widget/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/inherited_widget/windows/.gitignore @@ -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/ diff --git a/inherited_widget/windows/CMakeLists.txt b/inherited_widget/windows/CMakeLists.txt new file mode 100644 index 00000000..2236aafb --- /dev/null +++ b/inherited_widget/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(inherited_widget_sample 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 "inherited_widget_sample") + +# 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) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_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 "$") +# 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) diff --git a/inherited_widget/windows/flutter/CMakeLists.txt b/inherited_widget/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/inherited_widget/windows/flutter/CMakeLists.txt @@ -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} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/inherited_widget/windows/flutter/generated_plugin_registrant.cc b/inherited_widget/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/inherited_widget/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/inherited_widget/windows/flutter/generated_plugin_registrant.h b/inherited_widget/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/inherited_widget/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/inherited_widget/windows/flutter/generated_plugins.cmake b/inherited_widget/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/inherited_widget/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +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 $) + 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) diff --git a/inherited_widget/windows/runner/CMakeLists.txt b/inherited_widget/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/inherited_widget/windows/runner/CMakeLists.txt @@ -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) diff --git a/inherited_widget/windows/runner/Runner.rc b/inherited_widget/windows/runner/Runner.rc new file mode 100644 index 00000000..659ba9bf --- /dev/null +++ b/inherited_widget/windows/runner/Runner.rc @@ -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", "com.example" "\0" + VALUE "FileDescription", "inherited_widget_sample" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "inherited_widget_sample" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "inherited_widget_sample.exe" "\0" + VALUE "ProductName", "inherited_widget_sample" "\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 diff --git a/inherited_widget/windows/runner/flutter_window.cpp b/inherited_widget/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/inherited_widget/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#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( + 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 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); +} diff --git a/inherited_widget/windows/runner/flutter_window.h b/inherited_widget/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/inherited_widget/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#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_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/inherited_widget/windows/runner/main.cpp b/inherited_widget/windows/runner/main.cpp new file mode 100644 index 00000000..a95edb7e --- /dev/null +++ b/inherited_widget/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 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"inherited_widget_sample", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/inherited_widget/windows/runner/resource.h b/inherited_widget/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/inherited_widget/windows/runner/resource.h @@ -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 diff --git a/inherited_widget/windows/runner/resources/app_icon.ico b/inherited_widget/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/inherited_widget/windows/runner/resources/app_icon.ico differ diff --git a/inherited_widget/windows/runner/runner.exe.manifest b/inherited_widget/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/inherited_widget/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/inherited_widget/windows/runner/utils.cpp b/inherited_widget/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/inherited_widget/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +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 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::vector 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; +} diff --git a/inherited_widget/windows/runner/utils.h b/inherited_widget/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/inherited_widget/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// 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, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/inherited_widget/windows/runner/win32_window.cpp b/inherited_widget/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/inherited_widget/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#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(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( + 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(origin.x), + static_cast(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(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(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(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( + 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)); + } +} diff --git a/inherited_widget/windows/runner/win32_window.h b/inherited_widget/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/inherited_widget/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// 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_ diff --git a/integration_tests/lib/integration_tests.dart b/integration_tests/lib/integration_tests.dart index dda79c03..f11b16a7 100644 --- a/integration_tests/lib/integration_tests.dart +++ b/integration_tests/lib/integration_tests.dart @@ -1,172 +1,152 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - library integration_tests; -import 'package:flutter_driver/flutter_driver.dart'; -import 'package:test/test.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; import 'page_objects/page_objects.dart'; -void main() { - group('Todo App Test', () { - FlutterDriver driver; - HomeTestScreen homeScreen; +void run({required Future Function() appBuilder}) { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - setUpAll(() async { - driver = await FlutterDriver.connect(); - homeScreen = HomeTestScreen(driver); - }); + testWidgets('Todo App Test', (WidgetTester tester) async { + final app = await appBuilder(); + final homeScreen = HomeTestScreen(tester); - tearDownAll(() async { - if (driver != null) { - await driver.close(); - } - }); + // Build the app + await tester.pumpWidget(app); - test('should show a loading screen while the todos are fetched', () async { - expect(await homeScreen.isLoading(), isTrue); - }); + // should show a loading screen while the todos are fetched + expect(await homeScreen.isLoading(), isTrue); - test('should start with a list of Todos', () async { - expect(await homeScreen.isReady(), isTrue); - expect(await homeScreen.todoList.todoItem('1').isVisible, isTrue); - expect(await homeScreen.todoList.todoItem('2').isVisible, isTrue); - expect(await homeScreen.todoList.todoItem('3').isVisible, isTrue); - expect(await homeScreen.todoList.todoItem('4').isVisible, isTrue); - expect(await homeScreen.todoList.todoItem('5').isVisible, isTrue); - }); + // should start with a list of Todos + expect(await homeScreen.isReady(), isTrue); + expect(await homeScreen.todoList.todoItem('1').isVisible, isTrue); + expect(await homeScreen.todoList.todoItem('2').isVisible, isTrue); + expect(await homeScreen.todoList.todoItem('3').isVisible, isTrue); + expect(await homeScreen.todoList.todoItem('4').isVisible, isTrue); + expect(await homeScreen.todoList.todoItem('5').isVisible, isTrue); - test('should be able to click on an item to see details', () async { - final detailsScreen = await homeScreen.todoList.todoItem('2').tap(); - expect(await detailsScreen.task, isNotEmpty); - expect(await detailsScreen.note, isNotEmpty); + // should be able to click on an item to see details + var detailsScreen = await homeScreen.todoList.todoItem('2').tap(); + expect(await detailsScreen.isReady(), isTrue); + expect(await detailsScreen.task, isNotEmpty); + expect(await detailsScreen.note, isNotEmpty); - final editScreen = detailsScreen.tapEditTodoButton(); - - expect(await editScreen.isReady(), isTrue); + var editScreen = await detailsScreen.tapEditTodoButton(); - await editScreen.tapBackButton(); - }); - - test('should be able to delete a todo on the details screen', () async { - final detailsScreen = DetailsTestScreen(driver); - - await detailsScreen.tapDeleteButton(); - - expect(await homeScreen.todoList.todoItem('2').isAbsent, isTrue, - reason: 'TodoItem2 should be absent'); - expect(await homeScreen.snackbarVisible, isTrue, - reason: 'snackbar should be visible'); - }); - - test('should filter to completed todos', () async { - await homeScreen.tapFilterButton().tapShowCompleted(); - - expect(await homeScreen.todoList.todoItem('3').isVisible, isTrue); - expect(await homeScreen.todoList.todoItem('5').isVisible, isTrue); - }); - - test('should filter to active todos', () async { - await homeScreen.tapFilterButton().tapShowActive(); - - expect(await homeScreen.todoList.todoItem('1').isVisible, isTrue); - expect(await homeScreen.todoList.todoItem('4').isVisible, isTrue); - }); - - test('should once again filter to all todos', () async { - await homeScreen.tapFilterButton().tapShowAll(); - - expect(await homeScreen.todoList.todoItem('1').isVisible, isTrue); - expect(await homeScreen.todoList.todoItem('3').isVisible, isTrue); - expect(await homeScreen.todoList.todoItem('4').isVisible, isTrue); - expect(await homeScreen.todoList.todoItem('5').isVisible, isTrue); - }); - - test('should be able to view stats', () async { - final stats = await homeScreen.tapStatsTab(); - - expect(await stats.numActive, 2); - expect(await stats.numCompleted, 2); - }); - - test('should be able to toggle a todo complete', () async { - await homeScreen.tapTodosTab().todoItem('1').tapCheckbox(); - final stats = homeScreen.tapStatsTab(); - - // This is a hacky way to check if the tapping the checkbox was - // successful. Would be better to have an `isChecked` method from the - // driver or perhaps need to write a custom Matcher. - expect(await stats.numActive, 1); - expect(await stats.numCompleted, 3); - }); - - test('should be able to clear the completed todos', () async { - await homeScreen.tapExtraActionsButton().tapClearCompleted(); - - final stats = homeScreen.tapStatsTab(); - - expect(await stats.numActive, 1); - expect(await stats.numCompleted, 0); - }); - - test('should be able to toggle all todos complete', () async { - await homeScreen.tapExtraActionsButton().tapToggleAll(); - - expect(await homeScreen.stats.numActive, 0); - expect(await homeScreen.stats.numCompleted, 1); - }); - - test('should be able to add a todo', () async { - final task = 'Plan day trip to pyramids'; - final note = 'Take picture next to Great Pyramid of Giza!'; - - // init to home screen - await homeScreen.tapTodosTab(); - expect(await homeScreen.isReady(), isTrue); - - // go to add screen and enter a _todo - final addScreen = homeScreen.tapAddTodoButton(); - await addScreen.enterTask(task); - await addScreen.enterNote(note); - - // save and return to home screen and find new _todo - await addScreen.tapSaveNewButton(); - expect(await homeScreen.isReady(), true); - expect(await driver.getText(find.text(task)), task); - }); - - test('should be able to modify a todo', () async { - final task = 'Plan day trip to pyramids'; - final taskEdit = 'Plan full day trip to pyramids'; - final noteEdit = - 'Have lunch next to Great Pyramid of Giza and take pictures!'; + expect(await editScreen.isReady(), isTrue); + + await editScreen.tapBackButton(); - // init to home screen - await homeScreen.tapTodosTab(); - expect(await homeScreen.isReady(), isTrue); - - // find the _todo text to edit and go to details screen - final detailsScreen = await homeScreen.tapTodo(task); - expect(await detailsScreen.isReady(), isTrue); - - // go to edit screen and edit this _todo - final editScreen = detailsScreen.tapEditTodoButton(); - expect(await editScreen.isReady(), isTrue); - await editScreen.editTask(taskEdit); - await editScreen.editNote(noteEdit); - - // save and return to details screen - await editScreen.tapSaveFab(); - expect(await detailsScreen.isReady(), isTrue); - expect(await driver.getText(find.text(taskEdit)), taskEdit); - expect(await driver.getText(find.text(noteEdit)), noteEdit); - - // check shows up on home screen - await detailsScreen.tapBackButton(); - expect(await homeScreen.isReady(), isTrue); - expect(await driver.getText(find.text(taskEdit)), taskEdit); - }); + // should be able to delete a todo on the details screen + await detailsScreen.tapDeleteButton(); + + expect( + await homeScreen.todoList.todoItem('2').isAbsent, + isTrue, + reason: 'TodoItem2 should be absent', + ); + + expect( + await homeScreen.snackbarVisible, + isTrue, + reason: 'snackbar should be visible', + ); + + // should filter to completed todos + await (await homeScreen.tapFilterButton()).tapShowCompleted(); + + expect(await homeScreen.todoList.todoItem('3').isVisible, isTrue); + expect(await homeScreen.todoList.todoItem('5').isVisible, isTrue); + + // should filter to active todos + await (await homeScreen.tapFilterButton()).tapShowActive(); + expect(await homeScreen.todoList.todoItem('1').isVisible, isTrue); + expect(await homeScreen.todoList.todoItem('4').isVisible, isTrue); + + // should once again filter to all todos + await (await homeScreen.tapFilterButton()).tapShowAll(); + expect(await homeScreen.todoList.todoItem('1').isVisible, isTrue); + expect(await homeScreen.todoList.todoItem('3').isVisible, isTrue); + expect(await homeScreen.todoList.todoItem('4').isVisible, isTrue); + expect(await homeScreen.todoList.todoItem('5').isVisible, isTrue); + + // should be able to view stats + var stats = await homeScreen.tapStatsTab(); + expect(await stats.numActive, 2); + expect(await stats.numCompleted, 2); + + // should be able to toggle a todo complete + await (await homeScreen.tapTodosTab()).todoItem('1').tapCheckbox(); + stats = await homeScreen.tapStatsTab(); + + // This is a hacky way to check if the tapping the checkbox was + // successful. Would be better to have an `isChecked` method from the + // driver or perhaps need to write a custom Matcher. + expect(await stats.numActive, 1); + expect(await stats.numCompleted, 3); + + // should be able to clear the completed todos + await (await homeScreen.tapExtraActionsButton()).tapClearCompleted(); + + stats = await homeScreen.tapStatsTab(); + + expect(await stats.numActive, 1); + expect(await stats.numCompleted, 0); + + // should be able to toggle all todos complete + await (await homeScreen.tapExtraActionsButton()).tapToggleAll(); + + expect(await homeScreen.stats.numActive, 0); + expect(await homeScreen.stats.numCompleted, 1); + + // should be able to add a todo + final taskAdd = 'Plan day trip to pyramids'; + final noteAdd = 'Take picture next to Great Pyramid of Giza!'; + + // init to home screen + await homeScreen.tapTodosTab(); + expect(await homeScreen.isReady(), isTrue); + + // go to add screen and enter a _todo + final addScreen = await homeScreen.tapAddTodoButton(); + await addScreen.enterTask(taskAdd); + await addScreen.enterNote(noteAdd); + + // save and return to home screen and find new _todo + await addScreen.tapSaveNewButton(); + expect(await homeScreen.isReady(), isTrue); + expect(find.text(taskAdd), findsOneWidget); + + // should be able to modify a todo' + final taskEdit = 'Plan full day trip to pyramids'; + final noteEdit = + 'Have lunch next to Great Pyramid of Giza and take pictures!'; + + // init to home screen + await homeScreen.tapTodosTab(); + expect(await homeScreen.isReady(), isTrue); + + // find the _todo text to edit and go to details screen + detailsScreen = await homeScreen.tapTodo(taskAdd); + expect(await detailsScreen.isReady(), isTrue); + + // go to edit screen and edit this _todo + editScreen = await detailsScreen.tapEditTodoButton(); + expect(await editScreen.isReady(), isTrue); + await editScreen.editTask(taskEdit); + await editScreen.editNote(noteEdit); + + // save and return to details screen + await editScreen.tapSaveFab(); + expect(await detailsScreen.isReady(), isTrue); + expect(find.text(taskEdit), findsOneWidget); + expect(find.text(noteEdit), findsOneWidget); + + // check shows up on home screen + await detailsScreen.tapBackButton(); + expect(await homeScreen.isReady(), isTrue); + expect(find.text(taskEdit), findsOneWidget); }); } diff --git a/integration_tests/lib/page_objects/elements/extra_actions_element.dart b/integration_tests/lib/page_objects/elements/extra_actions_element.dart index 3662076b..6a85ebde 100644 --- a/integration_tests/lib/page_objects/elements/extra_actions_element.dart +++ b/integration_tests/lib/page_objects/elements/extra_actions_element.dart @@ -1,27 +1,24 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter_driver/flutter_driver.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'test_element.dart'; class ExtraActionsElement extends TestElement { - final _toggleAll = find.byValueKey('__markAllDone__'); - final _clearCompleted = find.byValueKey('__clearCompleted__'); + final _toggleAll = find.byKey(ValueKey('__markAllDone__')); + final _clearCompleted = find.byKey(ValueKey('__clearCompleted__')); - ExtraActionsElement(FlutterDriver driver) : super(driver); + ExtraActionsElement(WidgetTester tester) : super(tester); Future tapToggleAll() async { - await driver.tap(_toggleAll); + await tester.tap(_toggleAll); + await tester.pumpAndSettle(); return this; } Future tapClearCompleted() async { - await driver.tap(_clearCompleted); + await tester.tap(_clearCompleted); + await tester.pumpAndSettle(); return this; } diff --git a/integration_tests/lib/page_objects/elements/filters_element.dart b/integration_tests/lib/page_objects/elements/filters_element.dart index c0898612..e01e3582 100644 --- a/integration_tests/lib/page_objects/elements/filters_element.dart +++ b/integration_tests/lib/page_objects/elements/filters_element.dart @@ -1,25 +1,27 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter_driver/flutter_driver.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'test_element.dart'; class FiltersElement extends TestElement { - final _allFilter = find.byValueKey('__allFilter__'); - final _activeFilter = find.byValueKey('__activeFilter__'); - final _completedFilter = find.byValueKey('__completedFilter__'); + final _allFilter = find.byKey(ValueKey('__allFilter__')); + final _activeFilter = find.byKey(ValueKey('__activeFilter__')); + final _completedFilter = find.byKey(ValueKey('__completedFilter__')); - FiltersElement(FlutterDriver driver) : super(driver); + FiltersElement(WidgetTester tester) : super(tester); - Future tapShowAll() async => await driver.tap(_allFilter); + Future tapShowAll() async { + await tester.tap(_allFilter); + await tester.pumpAndSettle(); + } - Future tapShowActive() async => await driver.tap(_activeFilter); + Future tapShowActive() async { + await tester.tap(_activeFilter); + await tester.pumpAndSettle(); + } - Future tapShowCompleted() async { - return await driver.tap(_completedFilter); + Future tapShowCompleted() async { + await tester.tap(_completedFilter); + await tester.pumpAndSettle(); } } diff --git a/integration_tests/lib/page_objects/elements/stats_element.dart b/integration_tests/lib/page_objects/elements/stats_element.dart index 5bd72f68..c1b90020 100644 --- a/integration_tests/lib/page_objects/elements/stats_element.dart +++ b/integration_tests/lib/page_objects/elements/stats_element.dart @@ -1,22 +1,17 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter_driver/flutter_driver.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'test_element.dart'; class StatsElement extends TestElement { - final _activeItemsFinder = find.byValueKey('__statsActiveItems__'); - final _completedItemsFinder = find.byValueKey('__statsCompletedItems__'); + final _activeItemsFinder = find.byKey(ValueKey('__statsActiveItems__')); + final _completedItemsFinder = find.byKey(ValueKey('__statsCompletedItems__')); - StatsElement(FlutterDriver driver) : super(driver); + StatsElement(WidgetTester tester) : super(tester); Future get numActive async => - int.parse((await driver.getText(_activeItemsFinder))); + int.parse(tester.widget(_activeItemsFinder).data!); Future get numCompleted async => - int.parse((await driver.getText(_completedItemsFinder))); + int.parse(tester.widget(_completedItemsFinder).data!); } diff --git a/integration_tests/lib/page_objects/elements/test_element.dart b/integration_tests/lib/page_objects/elements/test_element.dart index ef46afec..91a861bc 100644 --- a/integration_tests/lib/page_objects/elements/test_element.dart +++ b/integration_tests/lib/page_objects/elements/test_element.dart @@ -1,11 +1,7 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter_driver/flutter_driver.dart'; +import 'package:flutter_test/flutter_test.dart'; abstract class TestElement { - final FlutterDriver driver; + final WidgetTester tester; - TestElement(this.driver); + TestElement(this.tester); } diff --git a/integration_tests/lib/page_objects/elements/todo_item_element.dart b/integration_tests/lib/page_objects/elements/todo_item_element.dart index 87dcc40e..abb992d1 100644 --- a/integration_tests/lib/page_objects/elements/todo_item_element.dart +++ b/integration_tests/lib/page_objects/elements/todo_item_element.dart @@ -1,10 +1,5 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter_driver/flutter_driver.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; import '../screens/details_test_screen.dart'; import '../utils.dart'; @@ -13,35 +8,35 @@ import 'test_element.dart'; class TodoItemElement extends TestElement { final String id; - TodoItemElement(this.id, FlutterDriver driver) : super(driver); + TodoItemElement(this.id, WidgetTester tester) : super(tester); - SerializableFinder get _taskFinder => - find.byValueKey('TodoItem__${id}__Task'); + Finder get _taskFinder => find.byKey(ValueKey('TodoItem__${id}__Task')); - SerializableFinder get _checkboxFinder => - find.byValueKey('TodoItem__${id}__Checkbox'); + Finder get _checkboxFinder => + find.byKey(ValueKey('TodoItem__${id}__Checkbox')); - SerializableFinder get _todoItemFinder => find.byValueKey('TodoItem__${id}'); + Finder get _todoItemFinder => find.byKey(ValueKey('TodoItem__${id}')); - Future get isVisible => widgetExists(driver, _todoItemFinder); + Future get isVisible => widgetExists(tester, _todoItemFinder); - Future get isAbsent => widgetAbsent(driver, _todoItemFinder); + Future get isAbsent => widgetAbsent(tester, _todoItemFinder); - Future get task async => await driver.getText(_taskFinder); + Future get task async => tester.widget(_taskFinder).data!; Future get note async => - await driver.getText(find.byValueKey('TodoItem__${id}__Note')); + tester.widget(find.byKey(ValueKey('TodoItem__${id}__Note'))).data!; Future tapCheckbox() async { - await driver.tap(_checkboxFinder); - await driver.waitUntilNoTransientCallbacks(); + await tester.tap(_checkboxFinder); + await tester.pumpAndSettle(); return this; } - DetailsTestScreen tap() { - driver.tap(_taskFinder); + Future tap() async { + await tester.tap(_taskFinder); + await tester.pumpAndSettle(); - return DetailsTestScreen(driver); + return DetailsTestScreen(tester); } } diff --git a/integration_tests/lib/page_objects/elements/todo_list_element.dart b/integration_tests/lib/page_objects/elements/todo_list_element.dart index 6a8f7657..1c44fbb3 100644 --- a/integration_tests/lib/page_objects/elements/todo_list_element.dart +++ b/integration_tests/lib/page_objects/elements/todo_list_element.dart @@ -1,36 +1,28 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter_driver/flutter_driver.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; import '../utils.dart'; import 'test_element.dart'; import 'todo_item_element.dart'; class TodoListElement extends TestElement { - final _todoListFinder = find.byValueKey('__todoList__'); - final _loadingFinder = find.byValueKey('__todosLoading__'); - - TodoListElement(FlutterDriver driver) : super(driver); - - Future get isLoading { - // We need to run this command "unsynchronized". This means it immediately - // checks if the loading widget is on screen, rather than waiting for any - // pending animations to complete. - // - // Since the CircularProgressIndicator runs a continuous animation, if we - // do not `runUnsynchronized`, this check will never work. - return driver.runUnsynchronized(() { - return widgetExists(driver, _loadingFinder); - }); + final _todoListFinder = find.byKey(ValueKey('__todoList__')); + final _loadingFinder = find.byKey(ValueKey('__todosLoading__')); + + TodoListElement(WidgetTester tester) : super(tester); + + Future get isLoading async { + await tester.pump(); + + return widgetExists(tester, _loadingFinder); } - Future get isReady => widgetExists(driver, _todoListFinder); + Future get isReady async { + await tester.pumpAndSettle(); + return widgetExists(tester, _todoListFinder); + } - TodoItemElement todoItem(String id) => TodoItemElement(id, driver); + TodoItemElement todoItem(String id) => TodoItemElement(id, tester); - TodoItemElement todoItemAbsent(String id) => TodoItemElement(id, driver); + TodoItemElement todoItemAbsent(String id) => TodoItemElement(id, tester); } diff --git a/integration_tests/lib/page_objects/page_objects.dart b/integration_tests/lib/page_objects/page_objects.dart index 8d59758e..d26dac6a 100644 --- a/integration_tests/lib/page_objects/page_objects.dart +++ b/integration_tests/lib/page_objects/page_objects.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - export 'screens/add_test_screen.dart'; export 'screens/details_test_screen.dart'; export 'screens/home_test_screen.dart'; diff --git a/integration_tests/lib/page_objects/screens/add_test_screen.dart b/integration_tests/lib/page_objects/screens/add_test_screen.dart index c2d8a81a..cf5ef5dd 100644 --- a/integration_tests/lib/page_objects/screens/add_test_screen.dart +++ b/integration_tests/lib/page_objects/screens/add_test_screen.dart @@ -1,48 +1,45 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter_driver/flutter_driver.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; import '../utils.dart'; import 'test_screen.dart'; class AddTestScreen extends TestScreen { - final _addScreenFinder = find.byValueKey('__addTodoScreen__'); + final _addScreenFinder = find.byKey(ValueKey('__addTodoScreen__')); final _backButtonFinder = find.byTooltip('Back'); - final _saveNewButtonFinder = find.byValueKey('__saveNewTodo__'); - final _taskFieldFinder = find.byValueKey('__taskField__'); - final _noteFieldFinder = find.byValueKey('__noteField__'); + final _saveNewButtonFinder = find.byKey(ValueKey('__saveNewTodo__')); + final _taskFieldFinder = find.byKey(ValueKey('__taskField__')); + final _noteFieldFinder = find.byKey(ValueKey('__noteField__')); - AddTestScreen(FlutterDriver driver) : super(driver); + AddTestScreen(WidgetTester tester) : super(tester); @override - Future isReady({Duration timeout}) => - widgetExists(driver, _addScreenFinder); + Future isReady({Duration? timeout}) => + widgetExists(tester, _addScreenFinder); - Future tapBackButton() async { - await driver.tap(_backButtonFinder); + Future tapBackButton() async { + await tester.tap(_backButtonFinder); + await tester.pumpAndSettle(); return this; } - Future enterTask(String task) async { + Future enterTask(String task) async { // must set focus to 'enable' keyboard even though focus already set - await driver.tap(_taskFieldFinder); - await driver.enterText(task); - await driver.waitFor(find.text(task)); + await tester.tap(_taskFieldFinder); + await tester.enterText(_taskFieldFinder, task); + await tester.pumpAndSettle(); } - Future enterNote(String note) async { + Future enterNote(String note) async { // must set focus to 'enable' keyboard even though focus already set - await driver.tap(_noteFieldFinder); - await driver.enterText(note); - await driver.waitFor(find.text(note)); + await tester.tap(_noteFieldFinder); + await tester.enterText(_noteFieldFinder, note); + await tester.pumpAndSettle(); } - Future tapSaveNewButton() async { - await driver.tap(_saveNewButtonFinder); + Future tapSaveNewButton() async { + await tester.tap(_saveNewButtonFinder); + await tester.pumpAndSettle(); } } diff --git a/integration_tests/lib/page_objects/screens/details_test_screen.dart b/integration_tests/lib/page_objects/screens/details_test_screen.dart index f934b787..768cd89c 100644 --- a/integration_tests/lib/page_objects/screens/details_test_screen.dart +++ b/integration_tests/lib/page_objects/screens/details_test_screen.dart @@ -1,51 +1,53 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter_driver/flutter_driver.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; import '../utils.dart'; import 'edit_test_screen.dart'; import 'test_screen.dart'; class DetailsTestScreen extends TestScreen { - final _detailsScreenFinder = find.byValueKey('__todoDetailsScreen__'); - final _deleteButtonFinder = find.byValueKey('__deleteTodoFab__'); - final _checkboxFinder = find.byValueKey('DetailsTodo__Checkbox'); - final _taskFinder = find.byValueKey('DetailsTodo__Task'); - final _noteFinder = find.byValueKey('DetailsTodo__Note'); - final _editTodoFabFinder = find.byValueKey('__editTodoFab__'); + final _detailsScreenFinder = find.byKey(ValueKey('__todoDetailsScreen__')); + final _deleteButtonFinder = find.byKey(ValueKey('__deleteTodoFab__')); + final _checkboxFinder = find.byKey(ValueKey('DetailsTodo__Checkbox')); + final _taskFinder = find.byKey(ValueKey('DetailsTodo__Task')); + final _noteFinder = find.byKey(ValueKey('DetailsTodo__Note')); + final _editTodoFabFinder = find.byKey(ValueKey('__editTodoFab__')); final _backButtonFinder = find.byTooltip('Back'); - DetailsTestScreen(FlutterDriver driver) : super(driver); + DetailsTestScreen(WidgetTester tester) : super(tester); @override - Future isReady({Duration timeout}) => - widgetExists(driver, _detailsScreenFinder, timeout: timeout); + Future isReady() async { + await tester.pumpAndSettle(); + + return widgetExists(tester, _detailsScreenFinder); + } - Future get task => driver.getText(_taskFinder); + String get task => tester.widget(_taskFinder).data!; - Future get note => driver.getText(_noteFinder); + String get note => tester.widget(_noteFinder).data!; Future tapCheckbox() async { - await driver.tap(_checkboxFinder); + await tester.tap(_checkboxFinder); + await tester.pumpAndSettle(); return this; } - EditTestScreen tapEditTodoButton() { - driver.tap(_editTodoFabFinder); + Future tapEditTodoButton() async { + await tester.tap(_editTodoFabFinder); + await tester.pumpAndSettle(); - return EditTestScreen(driver); + return EditTestScreen(tester); } - Future tapDeleteButton() async { - await driver.tap(_deleteButtonFinder); + Future tapDeleteButton() async { + await tester.tap(_deleteButtonFinder); + await tester.pumpAndSettle(); } - Future tapBackButton() async { - return await driver.tap(_backButtonFinder); + Future tapBackButton() async { + await tester.tap(_backButtonFinder); + await tester.pumpAndSettle(); } } diff --git a/integration_tests/lib/page_objects/screens/edit_test_screen.dart b/integration_tests/lib/page_objects/screens/edit_test_screen.dart index 38a63cf5..08f8d98d 100644 --- a/integration_tests/lib/page_objects/screens/edit_test_screen.dart +++ b/integration_tests/lib/page_objects/screens/edit_test_screen.dart @@ -1,46 +1,45 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter_driver/flutter_driver.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; import '../utils.dart'; import 'test_screen.dart'; class EditTestScreen extends TestScreen { - final _editScreenFinder = find.byValueKey('__editTodoScreen__'); + final _editScreenFinder = find.byKey(ValueKey('__editTodoScreen__')); final _backButtonFinder = find.byTooltip('Back'); - final _taskFieldFinder = find.byValueKey('__taskField__'); - final _noteFieldFinder = find.byValueKey('__noteField__'); - final _saveFabFinder = find.byValueKey('__saveTodoFab__'); + final _taskFieldFinder = find.byKey(ValueKey('__taskField__')); + final _noteFieldFinder = find.byKey(ValueKey('__noteField__')); + final _saveFabFinder = find.byKey(ValueKey('__saveTodoFab__')); - EditTestScreen(FlutterDriver driver) : super(driver); + EditTestScreen(WidgetTester tester) : super(tester); @override - Future isReady({Duration timeout}) => - widgetExists(driver, _editScreenFinder, timeout: timeout); + Future isReady() async { + await tester.pumpAndSettle(); + + return widgetExists(tester, _editScreenFinder); + } Future tapBackButton() async { - await driver.tap(_backButtonFinder); + await tester.tap(_backButtonFinder); + await tester.pumpAndSettle(); } Future editTask(String task) async { // must set focus to 'enable' keyboard even though focus already set - await driver.tap(_taskFieldFinder); - await driver.enterText(task); - await driver.waitFor(find.text(task)); + await tester.tap(_taskFieldFinder); + await tester.enterText(_taskFieldFinder, task); + await tester.pumpAndSettle(); } Future editNote(String note) async { // must set focus to 'enable' keyboard even though focus already set - await driver.tap(_noteFieldFinder); - await driver.enterText(note); - await driver.waitFor(find.text(note)); + await tester.tap(_noteFieldFinder); + await tester.enterText(_noteFieldFinder, note); + await tester.pumpAndSettle(); } Future tapSaveFab() async { - await driver.tap(_saveFabFinder); + await tester.tap(_saveFabFinder); } } diff --git a/integration_tests/lib/page_objects/screens/home_test_screen.dart b/integration_tests/lib/page_objects/screens/home_test_screen.dart index 16628e65..e45bbb50 100644 --- a/integration_tests/lib/page_objects/screens/home_test_screen.dart +++ b/integration_tests/lib/page_objects/screens/home_test_screen.dart @@ -1,10 +1,5 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter_driver/flutter_driver.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'package:integration_tests/page_objects/page_objects.dart'; import '../elements/extra_actions_element.dart'; @@ -15,66 +10,74 @@ import '../utils.dart'; import 'test_screen.dart'; class HomeTestScreen extends TestScreen { - final _filterButtonFinder = find.byValueKey('__filterButton__'); - final _extraActionsButtonFinder = find.byValueKey('__extraActionsButton__'); - final _todosTabFinder = find.byValueKey('__todoTab__'); - final _statsTabFinder = find.byValueKey('__statsTab__'); - final _snackbarFinder = find.byValueKey('__snackbar__'); - final _addTodoButtonFinder = find.byValueKey('__addTodoFab__'); + final _filterButtonFinder = find.byKey(ValueKey('__filterButton__')); + final _extraActionsButtonFinder = + find.byKey(ValueKey('__extraActionsButton__')); + final _todosTabFinder = find.byKey(ValueKey('__todoTab__')); + final _statsTabFinder = find.byKey(ValueKey('__statsTab__')); + final _snackbarFinder = find.byKey(ValueKey('__snackbar__')); + final _addTodoButtonFinder = find.byKey(ValueKey('__addTodoFab__')); - HomeTestScreen(FlutterDriver driver) : super(driver); + HomeTestScreen(WidgetTester tester) : super(tester); @override - Future isLoading({Duration timeout}) async => - TodoListElement(driver).isLoading; + Future isLoading() async => TodoListElement(tester).isLoading; @override - Future isReady({Duration timeout}) => TodoListElement(driver).isReady; + Future isReady() => TodoListElement(tester).isReady; TodoListElement get todoList { - return TodoListElement(driver); + return TodoListElement(tester); } StatsElement get stats { - return StatsElement(driver); + return StatsElement(tester); } - TodoListElement tapTodosTab() { - driver.tap(_todosTabFinder); + Future tapTodosTab() async { + await tester.tap(_todosTabFinder); + await tester.pumpAndSettle(); - return TodoListElement(driver); + return TodoListElement(tester); } - StatsElement tapStatsTab() { - driver.tap(_statsTabFinder); + Future tapStatsTab() async { + await tester.tap(_statsTabFinder); + await tester.pumpAndSettle(); - return StatsElement(driver); + return StatsElement(tester); } - FiltersElement tapFilterButton() { - driver.tap(_filterButtonFinder); + Future tapFilterButton() async { + await tester.tap(_filterButtonFinder); + await tester.pumpAndSettle(); - return FiltersElement(driver); + return FiltersElement(tester); } - ExtraActionsElement tapExtraActionsButton() { - driver.tap(_extraActionsButtonFinder); + Future tapExtraActionsButton() async { + await tester.tap(_extraActionsButtonFinder); + await tester.pumpAndSettle(); - return ExtraActionsElement(driver); + return ExtraActionsElement(tester); } - Future get snackbarVisible { - return widgetExists(driver, _snackbarFinder); + Future get snackbarVisible async { + await tester.pumpAndSettle(); + return widgetExists(tester, _snackbarFinder); } - AddTestScreen tapAddTodoButton() { - driver.tap(_addTodoButtonFinder); + Future tapAddTodoButton() async { + await tester.tap(_addTodoButtonFinder); + await tester.pumpAndSettle(); - return AddTestScreen(driver); + return AddTestScreen(tester); } - DetailsTestScreen tapTodo(String text) { - driver.tap(find.text(text)); - return DetailsTestScreen(driver); + Future tapTodo(String text) async { + await tester.tap(find.text(text)); + await tester.pumpAndSettle(); + + return DetailsTestScreen(tester); } } diff --git a/integration_tests/lib/page_objects/screens/test_screen.dart b/integration_tests/lib/page_objects/screens/test_screen.dart index ad7887a7..03bcad57 100644 --- a/integration_tests/lib/page_objects/screens/test_screen.dart +++ b/integration_tests/lib/page_objects/screens/test_screen.dart @@ -1,19 +1,13 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter_driver/flutter_driver.dart'; +import 'package:flutter_test/flutter_test.dart'; abstract class TestScreen { - final FlutterDriver driver; + final WidgetTester tester; - TestScreen(this.driver); + TestScreen(this.tester); - Future isLoading({Duration timeout}) async { - return !(await isReady(timeout: timeout)); + Future isLoading() async { + return !(await isReady()); } - Future isReady({Duration timeout}); + Future isReady(); } diff --git a/integration_tests/lib/page_objects/utils.dart b/integration_tests/lib/page_objects/utils.dart index 042f4117..905c1bdc 100644 --- a/integration_tests/lib/page_objects/utils.dart +++ b/integration_tests/lib/page_objects/utils.dart @@ -1,19 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter_driver/flutter_driver.dart'; +import 'package:flutter_test/flutter_test.dart'; Future widgetExists( - FlutterDriver driver, - SerializableFinder finder, { - Duration timeout, + WidgetTester tester, + Finder finder, { + Duration? timeout, }) async { try { - await driver.waitFor(finder, timeout: timeout); - + expect(finder, findsOneWidget); return true; } catch (_) { return false; @@ -21,13 +14,12 @@ Future widgetExists( } Future widgetAbsent( - FlutterDriver driver, - SerializableFinder finder, { - Duration timeout, + WidgetTester tester, + Finder finder, { + Duration? timeout, }) async { try { - await driver.waitForAbsent(finder, timeout: timeout); - + expect(finder, findsNothing); return true; } catch (_) { return false; diff --git a/integration_tests/pubspec.yaml b/integration_tests/pubspec.yaml index 05b8ee31..47eceb5a 100644 --- a/integration_tests/pubspec.yaml +++ b/integration_tests/pubspec.yaml @@ -2,19 +2,13 @@ name: integration_tests description: An integration test suite for the Flutter Architecture Samples environment: - sdk: ">=2.0.0-dev.28.0 <3.0.0" + sdk: ">=3.0.0 <4.0.0" dependencies: - test: flutter: sdk: flutter - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.0 - -dev_dependencies: - flutter_driver: + integration_test: sdk: flutter flutter_test: sdk: flutter + diff --git a/line_count.md b/line_count.md index 06c94c66..48c1e973 100644 --- a/line_count.md +++ b/line_count.md @@ -6,30 +6,27 @@ frameworks. This is an imperfect line count comparison -- some of the samples contain a bit more functionality / are structured a bit differently than others -- and should -be taken with a grain of salt. All generated files, blank lines and comment +be taken with a grain of salt. All generated files, blank lines and comment lines are removed for this comparison. -For authors of frameworks or samples (hey, I'm one of those!): Please do not +For authors of frameworks or samples (hey, I'm one of those!): Please do not take this comparison personally, nor should folks play "Code Golf" with the -samples to make them smaller, unless doing so improves the application overall. - +samples to make them smaller, unless doing so improves the application overall. + | *Sample* | *LOC (no comments)* | |--------|-------------------| -| scoped_model | 778 | -| mobx | 815 | -| change_notifier_provider | 830 | -| inherited_widget | 832 | -| mvc | 842 | -| vanilla | 842 | -| frideos_library | 878 | -| simple blocs | 1076 | -| built_redux | 1172 | -| mvu | 1191 | -| bloc | 1194 | -| bloc library | 1214 | -| mvi | 1244 | -| redux | 1362 | -| firestore_redux | 1429 | - -Note: This file was generated on 2020-01-10 14:59:25.151846Z using `scripts/line_counter.dart`. +| built_redux | 0 | +| firestore_redux | 0 | +| scoped_model | 767 | +| signals | 783 | +| mobx | 800 | +| inherited_widget | 815 | +| change_notifier_provider | 822 | +| vanilla | 837 | +| simple blocs | 1033 | +| bloc | 1123 | +| bloc library | 1191 | +| mvi | 1232 | +| redux | 1345 | +Note: This file was generated on Sun Sep 7 20:58:20 UTC 2025 using `scripts/line_counter.sh`. diff --git a/mobx/.metadata b/mobx/.metadata index 1b5cec02..fdb4416b 100644 --- a/mobx/.metadata +++ b/mobx/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: 27321ebbad34b0a3fafe99fac037102196d655ff - channel: stable + revision: "fcf2c11572af6f390246c056bc905eca609533a0" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: android + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: ios + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: linux + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: macos + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: web + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: windows + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/mobx/analysis_options.yaml b/mobx/analysis_options.yaml new file mode 100644 index 00000000..8d2d02a1 --- /dev/null +++ b/mobx/analysis_options.yaml @@ -0,0 +1,34 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# 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 +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + # The lint rules applied to this project can be customized in the + # 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 + # and their documentation is published at https://dart.dev/lints. + # + # 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 + # 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 + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/mobx/android/.gitignore b/mobx/android/.gitignore index bc2100d8..be3943c9 100644 --- a/mobx/android/.gitignore +++ b/mobx/android/.gitignore @@ -5,3 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/mobx/android/app/build.gradle b/mobx/android/app/build.gradle deleted file mode 100644 index 03fb603e..00000000 --- a/mobx/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.mobx" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/mobx/android/app/build.gradle.kts b/mobx/android/app/build.gradle.kts new file mode 100644 index 00000000..ab46c9bc --- /dev/null +++ b/mobx/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.mobx_sample" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.mobx_sample" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/mobx/android/app/src/debug/AndroidManifest.xml b/mobx/android/app/src/debug/AndroidManifest.xml index 066245a6..399f6981 100644 --- a/mobx/android/app/src/debug/AndroidManifest.xml +++ b/mobx/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/mobx/android/app/src/main/AndroidManifest.xml b/mobx/android/app/src/main/AndroidManifest.xml index 4d2b63e2..2763645a 100644 --- a/mobx/android/app/src/main/AndroidManifest.xml +++ b/mobx/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,25 @@ - - + + + @@ -27,4 +31,15 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + diff --git a/mobx/android/app/src/main/kotlin/com/example/mobx/MainActivity.kt b/mobx/android/app/src/main/kotlin/com/example/mobx/MainActivity.kt deleted file mode 100644 index 3495c266..00000000 --- a/mobx/android/app/src/main/kotlin/com/example/mobx/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.mobx - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/mobx/android/app/src/main/kotlin/com/example/mobx_sample/MainActivity.kt b/mobx/android/app/src/main/kotlin/com/example/mobx_sample/MainActivity.kt new file mode 100644 index 00000000..833ad31b --- /dev/null +++ b/mobx/android/app/src/main/kotlin/com/example/mobx_sample/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.mobx_sample + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/mobx/android/app/src/main/res/drawable-v21/launch_background.xml b/mobx/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/mobx/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/mobx/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/mobx/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index a3f285f9..db77bb4b 100644 Binary files a/mobx/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/mobx/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/mobx/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/mobx/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 5e6f3ac6..17987b79 100644 Binary files a/mobx/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/mobx/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/mobx/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/mobx/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 144d60be..09d43914 100644 Binary files a/mobx/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/mobx/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/mobx/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/mobx/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index deafae2d..d5f1c8d3 100644 Binary files a/mobx/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/mobx/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/mobx/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/mobx/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index d5614ac8..4d6372ee 100644 Binary files a/mobx/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/mobx/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/mobx/android/app/src/main/res/values-night/styles.xml b/mobx/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/mobx/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/mobx/android/app/src/main/res/values/styles.xml b/mobx/android/app/src/main/res/values/styles.xml index 00fa4417..cb1ef880 100644 --- a/mobx/android/app/src/main/res/values/styles.xml +++ b/mobx/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ - + + diff --git a/mobx/android/app/src/profile/AndroidManifest.xml b/mobx/android/app/src/profile/AndroidManifest.xml index 066245a6..399f6981 100644 --- a/mobx/android/app/src/profile/AndroidManifest.xml +++ b/mobx/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/mobx/android/build.gradle b/mobx/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/mobx/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/mobx/android/build.gradle.kts b/mobx/android/build.gradle.kts new file mode 100644 index 00000000..89176ef4 --- /dev/null +++ b/mobx/android/build.gradle.kts @@ -0,0 +1,21 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/mobx/android/gradle.properties b/mobx/android/gradle.properties index 38c8d454..f018a618 100644 --- a/mobx/android/gradle.properties +++ b/mobx/android/gradle.properties @@ -1,4 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/mobx/android/gradle/wrapper/gradle-wrapper.properties b/mobx/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..ac3b4792 100644 --- a/mobx/android/gradle/wrapper/gradle-wrapper.properties +++ b/mobx/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/mobx/android/settings.gradle b/mobx/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/mobx/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/mobx/android/settings.gradle.kts b/mobx/android/settings.gradle.kts new file mode 100644 index 00000000..ab39a10a --- /dev/null +++ b/mobx/android/settings.gradle.kts @@ -0,0 +1,25 @@ +pluginManagement { + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.7.3" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/mobx/integration_test/app_test.dart b/mobx/integration_test/app_test.dart new file mode 100644 index 00000000..807bd01a --- /dev/null +++ b/mobx/integration_test/app_test.dart @@ -0,0 +1,19 @@ +import 'package:integration_tests/integration_tests.dart' as integration_tests; +import 'package:mobx_sample/app.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; + +void main() { + integration_tests.run( + appBuilder: () async { + return MobxApp( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'mobx_test_${DateTime.now().toIso8601String()}', + await SharedPreferences.getInstance(), + ), + ), + ); + }, + ); +} diff --git a/mobx/ios/.gitignore b/mobx/ios/.gitignore index e96ef602..7a7f9873 100644 --- a/mobx/ios/.gitignore +++ b/mobx/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/mobx/ios/Flutter/AppFrameworkInfo.plist b/mobx/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f78..7c569640 100644 --- a/mobx/ios/Flutter/AppFrameworkInfo.plist +++ b/mobx/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 12.0 diff --git a/mobx/ios/Flutter/Debug.xcconfig b/mobx/ios/Flutter/Debug.xcconfig index e8efba11..ec97fc6f 100644 --- a/mobx/ios/Flutter/Debug.xcconfig +++ b/mobx/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/mobx/ios/Flutter/Release.xcconfig b/mobx/ios/Flutter/Release.xcconfig index 399e9340..c4855bfe 100644 --- a/mobx/ios/Flutter/Release.xcconfig +++ b/mobx/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/mobx/ios/Podfile b/mobx/ios/Podfile index b30a428b..e549ee22 100644 --- a/mobx/ios/Podfile +++ b/mobx/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -10,81 +10,34 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - generated_key_values + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' +flutter_ios_podfile_setup - # Plugin Pods +target 'Runner' do + use_frameworks! - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths end end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/mobx/ios/Runner.xcodeproj/project.pbxproj b/mobx/ios/Runner.xcodeproj/project.pbxproj index bc3ba7c9..2ee94714 100644 --- a/mobx/ios/Runner.xcodeproj/project.pbxproj +++ b/mobx/ios/Runner.xcodeproj/project.pbxproj @@ -3,23 +3,29 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - B940DB6F91D78988856B434D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C2A5CE66B2BCD66DABB1BA0 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -27,8 +33,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -38,23 +42,19 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 25D1A3170E4D49A14BD3B1AF /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7C2A5CE66B2BCD66DABB1BA0 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 82D122571FE649096AAA5892 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - B492BE0523C96C24DAD45E7E /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,21 +62,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - B940DB6F91D78988856B434D /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -90,8 +93,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - FE8088922888B11E12816E76 /* Pods */, - D4D570E764474C60C2363F40 /* Frameworks */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -99,6 +101,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -110,7 +113,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -119,47 +121,36 @@ path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, ); - name = "Supporting Files"; - sourceTree = ""; - }; - D4D570E764474C60C2363F40 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 7C2A5CE66B2BCD66DABB1BA0 /* Pods_Runner.framework */, + buildRules = ( ); - name = Frameworks; - sourceTree = ""; - }; - FE8088922888B11E12816E76 /* Pods */ = { - isa = PBXGroup; - children = ( - 25D1A3170E4D49A14BD3B1AF /* Pods-Runner.debug.xcconfig */, - B492BE0523C96C24DAD45E7E /* Pods-Runner.release.xcconfig */, - 82D122571FE649096AAA5892 /* Pods-Runner.profile.xcconfig */, + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, ); - name = Pods; - path = Pods; - sourceTree = ""; + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - A58A7FFFED3D999BFC70F620 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - C5836DAC2037C04040A76DF2 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -176,9 +167,14 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -186,7 +182,7 @@ }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -199,11 +195,19 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -220,20 +224,23 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -246,46 +253,17 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - A58A7FFFED3D999BFC70F620 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - C5836DAC2037C04040A76DF2 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -297,6 +275,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -319,9 +305,9 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -351,6 +337,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -359,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -375,18 +362,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.mobx; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mobxSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -394,11 +377,58 @@ }; name = Profile; }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mobxSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mobxSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mobxSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -428,6 +458,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -442,7 +473,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -452,9 +483,9 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -484,6 +515,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -492,11 +524,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -509,18 +542,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.mobx; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mobxSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -536,18 +565,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.mobx; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mobxSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -558,6 +583,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/mobx/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mobx/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/mobx/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/mobx/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/mobx/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mobx/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/mobx/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/mobx/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/mobx/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/mobx/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/mobx/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/mobx/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..e3773d42 100644 --- a/mobx/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/mobx/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + + + + + @@ -61,8 +73,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - - - diff --git a/mobx/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mobx/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/mobx/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/mobx/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/mobx/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/mobx/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/mobx/ios/Runner/AppDelegate.swift b/mobx/ios/Runner/AppDelegate.swift index 70693e4a..62666446 100644 --- a/mobx/ios/Runner/AppDelegate.swift +++ b/mobx/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ -import UIKit import Flutter +import UIKit -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d22f10b2..d36b1fab 100644 --- a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -107,6 +107,12 @@ "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" } ], "info" : { diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 980e5ad6..7353c41e 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index fd870289..797d452e 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 75e84cd1..6ed2d933 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 03ab8a84..4cd7b009 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index a03431cb..fe730945 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index f47613ee..321773cd 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 7f2230a9..797d452e 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 42315c6d..502f463a 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index f9882cc0..0ec30343 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 45537513..0ec30343 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 6360ea17..e9f5fea2 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 152d5e12..84ac32ae 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 310b0b8f..8953cba0 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 092b7bfe..0467bf12 100644 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/mobx/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/mobx/ios/Runner/Info.plist b/mobx/ios/Runner/Info.plist index e0432088..3f11e7e5 100644 --- a/mobx/ios/Runner/Info.plist +++ b/mobx/ios/Runner/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Mobx Sample CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -11,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - mobx + mobx_sample CFBundlePackageType APPL CFBundleShortVersionString @@ -39,7 +41,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/mobx/ios/Runner/Runner-Bridging-Header.h b/mobx/ios/Runner/Runner-Bridging-Header.h index 7335fdf9..308a2a56 100644 --- a/mobx/ios/Runner/Runner-Bridging-Header.h +++ b/mobx/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file +#import "GeneratedPluginRegistrant.h" diff --git a/mobx/ios/RunnerTests/RunnerTests.swift b/mobx/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/mobx/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/mobx/lib/add_todo_screen.dart b/mobx/lib/add_todo_screen.dart index 0234c3d3..ffda58ab 100644 --- a/mobx/lib/add_todo_screen.dart +++ b/mobx/lib/add_todo_screen.dart @@ -5,14 +5,16 @@ import 'package:todos_app_core/todos_app_core.dart'; class AddTodoScreen extends StatefulWidget { final void Function(Todo) onAdd; - const AddTodoScreen({@required this.onAdd}) - : super(key: ArchSampleKeys.addTodoScreen); + const AddTodoScreen({ + super.key = ArchSampleKeys.addTodoScreen, + required this.onAdd, + }); @override - _AddTodoScreenState createState() => _AddTodoScreenState(); + AddTodoScreenState createState() => AddTodoScreenState(); } -class _AddTodoScreenState extends State { +class AddTodoScreenState extends State { final _formKey = GlobalKey(); final _titleEditingController = TextEditingController(); final _notesEditingController = TextEditingController(); @@ -30,12 +32,10 @@ class _AddTodoScreenState extends State { final textTheme = Theme.of(context).textTheme; return Scaffold( - appBar: AppBar( - title: Text(localizations.addTodo), - ), + appBar: AppBar(title: Text(localizations.addTodo)), body: Form( key: _formKey, - autovalidate: false, + autovalidateMode: AutovalidateMode.onUnfocus, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -46,10 +46,10 @@ class _AddTodoScreenState extends State { decoration: InputDecoration( hintText: localizations.newTodoHint, ), - style: textTheme.headline, + style: textTheme.titleLarge, autofocus: true, validator: (val) { - return val.trim().isEmpty + return val == null || val.trim().isEmpty ? localizations.emptyTodoError : null; }, @@ -57,10 +57,10 @@ class _AddTodoScreenState extends State { TextFormField( key: ArchSampleKeys.noteField, controller: _notesEditingController, - style: textTheme.subhead, + style: textTheme.titleMedium, decoration: InputDecoration(hintText: localizations.notesHint), maxLines: 10, - ) + ), ], ), ), @@ -69,11 +69,13 @@ class _AddTodoScreenState extends State { key: ArchSampleKeys.saveNewTodo, tooltip: localizations.addTodo, onPressed: () { - if (_formKey.currentState.validate()) { - widget.onAdd(Todo( - task: _titleEditingController.text, - note: _notesEditingController.text, - )); + if (_formKey.currentState!.validate()) { + widget.onAdd( + Todo( + task: _titleEditingController.text, + note: _notesEditingController.text, + ), + ); } }, child: const Icon(Icons.add), diff --git a/mobx/lib/app.dart b/mobx/lib/app.dart index 4ff3841e..0e77e34f 100644 --- a/mobx/lib/app.dart +++ b/mobx/lib/app.dart @@ -12,7 +12,7 @@ import 'home/home_screen.dart'; class MobxApp extends StatelessWidget { final TodosRepository repository; - const MobxApp({Key key, @required this.repository}) : super(key: key); + const MobxApp({super.key, required this.repository}); @override Widget build(BuildContext context) { @@ -25,7 +25,8 @@ class MobxApp extends StatelessWidget { dispose: (_, store) => store.dispose(), // Clean up after we're done child: MaterialApp( initialRoute: ArchSampleRoutes.home, - theme: ArchSampleTheme.theme, + theme: ArchSampleTheme.lightTheme, + darkTheme: ArchSampleTheme.darkTheme, localizationsDelegates: [ MobxLocalizationsDelegate(), ArchSampleLocalizationsDelegate(), @@ -39,7 +40,7 @@ class MobxApp extends StatelessWidget { Navigator.pop(context); }, ); - } + }, }, ), ); diff --git a/mobx/lib/details_screen.dart b/mobx/lib/details_screen.dart index 65b80462..0a8830b6 100644 --- a/mobx/lib/details_screen.dart +++ b/mobx/lib/details_screen.dart @@ -9,8 +9,8 @@ class DetailsScreen extends StatelessWidget { final Todo todo; final void Function() onRemove; - const DetailsScreen({@required this.todo, @required this.onRemove}) - : super(key: ArchSampleKeys.todoDetailsScreen); + const DetailsScreen({required this.todo, required this.onRemove}) + : super(key: ArchSampleKeys.todoDetailsScreen); @override Widget build(BuildContext context) { @@ -23,7 +23,7 @@ class DetailsScreen extends StatelessWidget { tooltip: ArchSampleLocalizations.of(context).deleteTodo, icon: const Icon(Icons.delete), onPressed: onRemove, - ) + ), ], ), floatingActionButton: FloatingActionButton( @@ -31,7 +31,7 @@ class DetailsScreen extends StatelessWidget { onPressed: () { Navigator.push( context, - MaterialPageRoute( + MaterialPageRoute( builder: (context) => EditTodoScreen( todo: todo, onEdit: () => Navigator.pop(context), @@ -54,7 +54,7 @@ class DetailsScreen extends StatelessWidget { builder: (_) => Checkbox( key: ArchSampleKeys.detailsTodoItemCheckbox, value: todo.complete, - onChanged: (done) => todo.complete = done, + onChanged: (done) => todo.complete = done ?? false, ), ), ), @@ -63,15 +63,12 @@ class DetailsScreen extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: const EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), + padding: const EdgeInsets.only(top: 8.0, bottom: 16.0), child: Observer( builder: (context) => Text( todo.task, key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, ), ), ), @@ -79,9 +76,9 @@ class DetailsScreen extends StatelessWidget { builder: (_) => Text( todo.note, key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), - ) + ), ], ), ), diff --git a/mobx/lib/edit_todo_screen.dart b/mobx/lib/edit_todo_screen.dart index 9ab67e2c..bae188ed 100644 --- a/mobx/lib/edit_todo_screen.dart +++ b/mobx/lib/edit_todo_screen.dart @@ -6,16 +6,14 @@ class EditTodoScreen extends StatefulWidget { final void Function() onEdit; final Todo todo; - const EditTodoScreen({ - @required this.todo, - @required this.onEdit, - }) : super(key: ArchSampleKeys.editTodoScreen); + const EditTodoScreen({required this.todo, required this.onEdit}) + : super(key: ArchSampleKeys.editTodoScreen); @override - _EditTodoScreenState createState() => _EditTodoScreenState(); + EditTodoScreenState createState() => EditTodoScreenState(); } -class _EditTodoScreenState extends State { +class EditTodoScreenState extends State { final _formKey = GlobalKey(); @override @@ -31,26 +29,26 @@ class _EditTodoScreenState extends State { TextFormField( key: ArchSampleKeys.taskField, initialValue: widget.todo.task, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, decoration: InputDecoration( hintText: ArchSampleLocalizations.of(context).newTodoHint, ), validator: (val) { - return val.trim().isEmpty + return val == null || val.trim().isEmpty ? ArchSampleLocalizations.of(context).emptyTodoError : null; }, - onSaved: (value) => widget.todo.task = value, + onSaved: (value) => widget.todo.task = value ?? '', ), TextFormField( key: ArchSampleKeys.noteField, - initialValue: widget.todo.note ?? '', + initialValue: widget.todo.note, decoration: InputDecoration( hintText: ArchSampleLocalizations.of(context).notesHint, ), maxLines: 10, - onSaved: (value) => widget.todo.note = value, - ) + onSaved: (value) => widget.todo.note = value ?? '', + ), ], ), ), @@ -59,8 +57,8 @@ class _EditTodoScreenState extends State { key: ArchSampleKeys.saveTodoFab, tooltip: ArchSampleLocalizations.of(context).saveChanges, onPressed: () { - if (_formKey.currentState.validate()) { - _formKey.currentState.save(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); widget.onEdit(); } }, diff --git a/mobx/lib/home/extra_actions_button.dart b/mobx/lib/home/extra_actions_button.dart index 249f45a4..010852d9 100644 --- a/mobx/lib/home/extra_actions_button.dart +++ b/mobx/lib/home/extra_actions_button.dart @@ -1,16 +1,10 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:mobx_sample/stores/todo_store.dart'; import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; class ExtraActionsButton extends StatelessWidget { - const ExtraActionsButton({ - Key key, - }) : super(key: key); + const ExtraActionsButton({super.key}); @override Widget build(BuildContext context) { @@ -30,9 +24,11 @@ class ExtraActionsButton extends StatelessWidget { PopupMenuItem( key: ArchSampleKeys.toggleAll, value: ExtraAction.toggleAllComplete, - child: Text(store.hasPendingTodos - ? ArchSampleLocalizations.of(context).markAllComplete - : ArchSampleLocalizations.of(context).markAllIncomplete), + child: Text( + store.hasPendingTodos + ? ArchSampleLocalizations.of(context).markAllComplete + : ArchSampleLocalizations.of(context).markAllIncomplete, + ), ), PopupMenuItem( key: ArchSampleKeys.clearCompleted, diff --git a/mobx/lib/home/filter_button.dart b/mobx/lib/home/filter_button.dart index d06d1e56..9958758e 100644 --- a/mobx/lib/home/filter_button.dart +++ b/mobx/lib/home/filter_button.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx_sample/stores/todo_store.dart'; @@ -11,7 +7,7 @@ import 'package:todos_app_core/todos_app_core.dart'; class FilterButton extends StatelessWidget { final bool isActive; - const FilterButton({this.isActive, Key key}) : super(key: key); + const FilterButton({super.key, required this.isActive}); @override Widget build(BuildContext context) { @@ -39,12 +35,13 @@ class FilterButton extends StatelessWidget { } List> _items( - BuildContext context, TodoStore store) { - final activeStyle = Theme.of(context) - .textTheme - .body1 - .copyWith(color: Theme.of(context).accentColor); - final defaultStyle = Theme.of(context).textTheme.body1; + BuildContext context, + TodoStore store, + ) { + final defaultStyle = Theme.of(context).textTheme.bodyMedium; + final activeStyle = defaultStyle?.copyWith( + color: Theme.of(context).colorScheme.secondary, + ); return [ PopupMenuItem( @@ -52,8 +49,9 @@ class FilterButton extends StatelessWidget { value: VisibilityFilter.all, child: Text( ArchSampleLocalizations.of(context).showAll, - style: - store.filter == VisibilityFilter.all ? activeStyle : defaultStyle, + style: store.filter == VisibilityFilter.all + ? activeStyle + : defaultStyle, ), ), PopupMenuItem( diff --git a/mobx/lib/home/home_screen.dart b/mobx/lib/home/home_screen.dart index a52389e2..9985886e 100644 --- a/mobx/lib/home/home_screen.dart +++ b/mobx/lib/home/home_screen.dart @@ -13,20 +13,20 @@ import 'extra_actions_button.dart'; import 'filter_button.dart'; class HomeScreen extends StatefulWidget { - const HomeScreen(); + const HomeScreen({super.key}); @override - _HomeScreenState createState() => _HomeScreenState(); + HomeScreenState createState() => HomeScreenState(); } -class _HomeScreenState extends State { +class HomeScreenState extends State { // Because the state of the tabs is only a concern to the HomeScreen Widget, // it is stored as local state rather than in the TodoStore. // // In this case, there's no need for a fully generated Store class. Just // create a mobx Observable locally as part of the state class and use the // Observer Widget to listen for changes as with any Observable. - final _tab = Observable(_HomeScreenTab.todos); + final _tab = Observable(HomeScreenTab.todos); @override Widget build(BuildContext context) { @@ -35,9 +35,8 @@ class _HomeScreenState extends State { title: Text(MobxLocalizations.of(context).appTitle), actions: [ Observer( - builder: (_) => FilterButton( - isActive: _tab.value == _HomeScreenTab.todos, - ), + builder: (_) => + FilterButton(isActive: _tab.value == HomeScreenTab.todos), ), const ExtraActionsButton(), ], @@ -61,10 +60,9 @@ class _HomeScreenState extends State { } switch (_tab.value) { - case _HomeScreenTab.stats: + case HomeScreenTab.stats: return const StatsView(); - case _HomeScreenTab.todos: - default: + case HomeScreenTab.todos: return TodoListView( onRemove: (context, todo) { store.todos.remove(todo); @@ -78,16 +76,16 @@ class _HomeScreenState extends State { builder: (context) { return BottomNavigationBar( key: ArchSampleKeys.tabs, - currentIndex: _HomeScreenTab.values.indexOf(_tab.value), + currentIndex: HomeScreenTab.values.indexOf(_tab.value), onTap: (int index) { - runInAction(() => _tab.value = _HomeScreenTab.values[index]); + runInAction(() => _tab.value = HomeScreenTab.values[index]); }, items: [ - for (final tab in _HomeScreenTab.values) + for (final tab in HomeScreenTab.values) BottomNavigationBarItem( icon: Icon(tab.icon, key: tab.key), - title: Text(tab.title), - ) + label: tab.title, + ), ], ); }, @@ -96,7 +94,7 @@ class _HomeScreenState extends State { } void _displayRemovalNotification(BuildContext context, Todo todo) { - Scaffold.of(context).showSnackBar( + ScaffoldMessenger.of(context).showSnackBar( SnackBar( key: ArchSampleKeys.snackbar, duration: const Duration(seconds: 2), @@ -117,19 +115,19 @@ class _HomeScreenState extends State { } } -enum _HomeScreenTab { todos, stats } +enum HomeScreenTab { todos, stats } -extension TabExtensions on _HomeScreenTab { +extension TabExtensions on HomeScreenTab { IconData get icon { - return (this == _HomeScreenTab.todos) ? Icons.list : Icons.show_chart; + return (this == HomeScreenTab.todos) ? Icons.list : Icons.show_chart; } String get title { - return this == _HomeScreenTab.todos ? 'Todos' : 'Stats'; + return this == HomeScreenTab.todos ? 'Todos' : 'Stats'; } Key get key { - return this == _HomeScreenTab.stats + return this == HomeScreenTab.stats ? ArchSampleKeys.statsTab : ArchSampleKeys.todoTab; } diff --git a/mobx/lib/home/stats_view.dart b/mobx/lib/home/stats_view.dart index fab86e7d..03c6ea75 100644 --- a/mobx/lib/home/stats_view.dart +++ b/mobx/lib/home/stats_view.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx_sample/stores/todo_store.dart'; @@ -6,7 +5,7 @@ import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; class StatsView extends StatelessWidget { - const StatsView(); + const StatsView({super.key}); @override Widget build(BuildContext context) { @@ -20,7 +19,7 @@ class StatsView extends StatelessWidget { padding: const EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -29,7 +28,7 @@ class StatsView extends StatelessWidget { builder: (context) => Text( '${store.numCompleted}', key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ), @@ -37,7 +36,7 @@ class StatsView extends StatelessWidget { padding: const EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -46,10 +45,10 @@ class StatsView extends StatelessWidget { builder: (context) => Text( '${store.numPending}', key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), - ) + ), ], ), ); diff --git a/mobx/lib/home/todo_list_view.dart b/mobx/lib/home/todo_list_view.dart index 10ba77a9..fd33116a 100644 --- a/mobx/lib/home/todo_list_view.dart +++ b/mobx/lib/home/todo_list_view.dart @@ -10,7 +10,7 @@ import '../details_screen.dart'; class TodoListView extends StatelessWidget { final void Function(BuildContext context, Todo todo) onRemove; - TodoListView({Key key, @required this.onRemove}) : super(key: key); + const TodoListView({super.key, required this.onRemove}); @override Widget build(BuildContext context) { @@ -31,7 +31,7 @@ class TodoListView extends StatelessWidget { onTap: () { Navigator.push( context, - MaterialPageRoute( + MaterialPageRoute( builder: (_) { return DetailsScreen( todo: todo, @@ -48,14 +48,14 @@ class TodoListView extends StatelessWidget { builder: (_) => Checkbox( key: ArchSampleKeys.todoItemCheckbox(todo.id), value: todo.complete, - onChanged: (done) => todo.complete = done, + onChanged: (done) => todo.complete = done ?? false, ), ), title: Observer( builder: (context) => Text( todo.task, key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), subtitle: Observer( @@ -64,7 +64,7 @@ class TodoListView extends StatelessWidget { key: ArchSampleKeys.todoItemNote(todo.id), maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ), diff --git a/mobx/lib/localization.dart b/mobx/lib/localization.dart index a83b2f36..fffe9551 100644 --- a/mobx/lib/localization.dart +++ b/mobx/lib/localization.dart @@ -1,14 +1,10 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; class MobxLocalizations { static MobxLocalizations of(BuildContext context) { - return Localizations.of(context, MobxLocalizations); + return Localizations.of(context, MobxLocalizations)!; } String get appTitle => 'Todos with MobX'; diff --git a/mobx/lib/main.dart b/mobx/lib/main.dart index d2c75a27..69c76350 100644 --- a/mobx/lib/main.dart +++ b/mobx/lib/main.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:key_value_store_flutter/key_value_store_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; @@ -13,7 +12,7 @@ Future main() async { repository: LocalStorageRepository( localStorage: KeyValueStorage( 'mobx_todos', - FlutterKeyValueStore(await SharedPreferences.getInstance()), + await SharedPreferences.getInstance(), ), ), ), diff --git a/mobx/lib/main_web.dart b/mobx/lib/main_web.dart deleted file mode 100644 index d9b4785a..00000000 --- a/mobx/lib/main_web.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'dart:html'; - -import 'package:flutter/material.dart'; -import 'package:key_value_store_web/key_value_store_web.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -import 'app.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - runApp( - MobxApp( - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'mobx_todos', - WebKeyValueStore(window.localStorage), - ), - ), - ), - ); -} diff --git a/mobx/lib/models/todo.dart b/mobx/lib/models/todo.dart index 184f0de6..1a8f1230 100644 --- a/mobx/lib/models/todo.dart +++ b/mobx/lib/models/todo.dart @@ -5,14 +5,14 @@ part 'todo.g.dart'; /// A reactive class that holds information about a task that needs to be /// completed -class Todo = _Todo with _$Todo; - -abstract class _Todo with Store { - _Todo({ - String id, - this.task = '', - this.note = '', - this.complete = false, +class Todo = TodoBase with _$Todo; + +abstract class TodoBase with Store { + TodoBase({ + String? id, + this.task = '', // ignore: unused_element_parameter + this.note = '', // ignore: unused_element_parameter + this.complete = false, // ignore: unused_element_parameter }) : id = id ?? Uuid().generateV4(); final String id; @@ -34,7 +34,7 @@ abstract class _Todo with Store { @override bool operator ==(Object other) => identical(this, other) || - other is _Todo && + other is TodoBase && runtimeType == other.runtimeType && id == other.id && task == other.task && diff --git a/mobx/lib/models/todo.g.dart b/mobx/lib/models/todo.g.dart index 93b1baa7..62a8fa54 100644 --- a/mobx/lib/models/todo.g.dart +++ b/mobx/lib/models/todo.g.dart @@ -6,57 +6,60 @@ part of 'todo.dart'; // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers -mixin _$Todo on _Todo, Store { - final _$taskAtom = Atom(name: '_Todo.task'); +mixin _$Todo on TodoBase, Store { + late final _$taskAtom = Atom(name: 'TodoBase.task', context: context); @override String get task { - _$taskAtom.context.enforceReadPolicy(_$taskAtom); - _$taskAtom.reportObserved(); + _$taskAtom.reportRead(); return super.task; } @override set task(String value) { - _$taskAtom.context.conditionallyRunInAction(() { + _$taskAtom.reportWrite(value, super.task, () { super.task = value; - _$taskAtom.reportChanged(); - }, _$taskAtom, name: '${_$taskAtom.name}_set'); + }); } - final _$noteAtom = Atom(name: '_Todo.note'); + late final _$noteAtom = Atom(name: 'TodoBase.note', context: context); @override String get note { - _$noteAtom.context.enforceReadPolicy(_$noteAtom); - _$noteAtom.reportObserved(); + _$noteAtom.reportRead(); return super.note; } @override set note(String value) { - _$noteAtom.context.conditionallyRunInAction(() { + _$noteAtom.reportWrite(value, super.note, () { super.note = value; - _$noteAtom.reportChanged(); - }, _$noteAtom, name: '${_$noteAtom.name}_set'); + }); } - final _$completeAtom = Atom(name: '_Todo.complete'); + late final _$completeAtom = Atom(name: 'TodoBase.complete', context: context); @override bool get complete { - _$completeAtom.context.enforceReadPolicy(_$completeAtom); - _$completeAtom.reportObserved(); + _$completeAtom.reportRead(); return super.complete; } @override set complete(bool value) { - _$completeAtom.context.conditionallyRunInAction(() { + _$completeAtom.reportWrite(value, super.complete, () { super.complete = value; - _$completeAtom.reportChanged(); - }, _$completeAtom, name: '${_$completeAtom.name}_set'); + }); + } + + @override + String toString() { + return ''' +task: ${task}, +note: ${note}, +complete: ${complete} + '''; } } diff --git a/mobx/lib/models/todo_codec.dart b/mobx/lib/models/todo_codec.dart index f758c612..ec012382 100644 --- a/mobx/lib/models/todo_codec.dart +++ b/mobx/lib/models/todo_codec.dart @@ -21,12 +21,7 @@ class _TodoEncoder extends Converter { @override TodoEntity convert(Todo todo) { - return TodoEntity( - todo.task, - todo.id, - todo.note, - todo.complete, - ); + return TodoEntity(todo.task, todo.id, todo.note, todo.complete); } } @@ -37,7 +32,7 @@ class _TodoDecoder extends Converter { Todo convert(TodoEntity entity) { return Todo( task: entity.task, - complete: entity.complete ?? false, + complete: entity.complete, note: entity.note, id: entity.id, ); diff --git a/mobx/lib/stores/todo_store.dart b/mobx/lib/stores/todo_store.dart index 837943c6..5f445ddc 100644 --- a/mobx/lib/stores/todo_store.dart +++ b/mobx/lib/stores/todo_store.dart @@ -10,28 +10,28 @@ part 'todo_store.g.dart'; /// /// The TodoStore interacts with a TodosRepository to load and persist todos. It /// persists changes every time the list of todos is edited. -class TodoStore = _TodoStore with _$TodoStore; +class TodoStore = TodoStoreBase with _$TodoStore; -abstract class _TodoStore with Store { - _TodoStore( +abstract class TodoStoreBase with Store { + TodoStoreBase( this.repository, { - ObservableList todos, - this.filter = VisibilityFilter.all, - this.todosCodec = const TodoCodec(), - this.saveDelay = 500, + ObservableList? todos, + this.filter = VisibilityFilter.all, // ignore: unused_element_parameter + this.todosCodec = const TodoCodec(), // ignore: unused_element_parameter + this.saveDelay = 500, // ignore: unused_element_parameter }) : todos = todos ?? ObservableList(); final TodoCodec todosCodec; final TodosRepository repository; - final int saveDelay; + final int? saveDelay; final ObservableList todos; - ReactionDisposer _disposeSaveReaction; + late ReactionDisposer _disposeSaveReaction; @observable VisibilityFilter filter; @observable - ObservableFuture loader; + late ObservableFuture loader; @computed List get pendingTodos => @@ -61,7 +61,6 @@ abstract class _TodoStore with Store { case VisibilityFilter.completed: return completedTodos; case VisibilityFilter.all: - default: return todos; } } diff --git a/mobx/lib/stores/todo_store.g.dart b/mobx/lib/stores/todo_store.g.dart index 418616b2..f2b0bd05 100644 --- a/mobx/lib/stores/todo_store.g.dart +++ b/mobx/lib/stores/todo_store.g.dart @@ -6,111 +6,156 @@ part of 'todo_store.dart'; // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers -mixin _$TodoStore on _TodoStore, Store { - Computed> _$pendingTodosComputed; +mixin _$TodoStore on TodoStoreBase, Store { + Computed>? _$pendingTodosComputed; @override - List get pendingTodos => (_$pendingTodosComputed ??= - Computed>(() => super.pendingTodos)) - .value; - Computed> _$completedTodosComputed; + List get pendingTodos => + (_$pendingTodosComputed ??= Computed>( + () => super.pendingTodos, + name: 'TodoStoreBase.pendingTodos', + )).value; + Computed>? _$completedTodosComputed; @override - List get completedTodos => (_$completedTodosComputed ??= - Computed>(() => super.completedTodos)) - .value; - Computed _$hasCompletedTodosComputed; + List get completedTodos => + (_$completedTodosComputed ??= Computed>( + () => super.completedTodos, + name: 'TodoStoreBase.completedTodos', + )).value; + Computed? _$hasCompletedTodosComputed; @override - bool get hasCompletedTodos => (_$hasCompletedTodosComputed ??= - Computed(() => super.hasCompletedTodos)) - .value; - Computed _$hasPendingTodosComputed; + bool get hasCompletedTodos => (_$hasCompletedTodosComputed ??= Computed( + () => super.hasCompletedTodos, + name: 'TodoStoreBase.hasCompletedTodos', + )).value; + Computed? _$hasPendingTodosComputed; @override - bool get hasPendingTodos => (_$hasPendingTodosComputed ??= - Computed(() => super.hasPendingTodos)) - .value; - Computed _$numPendingComputed; + bool get hasPendingTodos => (_$hasPendingTodosComputed ??= Computed( + () => super.hasPendingTodos, + name: 'TodoStoreBase.hasPendingTodos', + )).value; + Computed? _$numPendingComputed; @override - int get numPending => - (_$numPendingComputed ??= Computed(() => super.numPending)).value; - Computed _$numCompletedComputed; + int get numPending => (_$numPendingComputed ??= Computed( + () => super.numPending, + name: 'TodoStoreBase.numPending', + )).value; + Computed? _$numCompletedComputed; @override - int get numCompleted => - (_$numCompletedComputed ??= Computed(() => super.numCompleted)) - .value; - Computed> _$visibleTodosComputed; + int get numCompleted => (_$numCompletedComputed ??= Computed( + () => super.numCompleted, + name: 'TodoStoreBase.numCompleted', + )).value; + Computed>? _$visibleTodosComputed; @override - List get visibleTodos => (_$visibleTodosComputed ??= - Computed>(() => super.visibleTodos)) - .value; + List get visibleTodos => + (_$visibleTodosComputed ??= Computed>( + () => super.visibleTodos, + name: 'TodoStoreBase.visibleTodos', + )).value; - final _$filterAtom = Atom(name: '_TodoStore.filter'); + late final _$filterAtom = Atom( + name: 'TodoStoreBase.filter', + context: context, + ); @override VisibilityFilter get filter { - _$filterAtom.context.enforceReadPolicy(_$filterAtom); - _$filterAtom.reportObserved(); + _$filterAtom.reportRead(); return super.filter; } @override set filter(VisibilityFilter value) { - _$filterAtom.context.conditionallyRunInAction(() { + _$filterAtom.reportWrite(value, super.filter, () { super.filter = value; - _$filterAtom.reportChanged(); - }, _$filterAtom, name: '${_$filterAtom.name}_set'); + }); } - final _$loaderAtom = Atom(name: '_TodoStore.loader'); + late final _$loaderAtom = Atom( + name: 'TodoStoreBase.loader', + context: context, + ); @override ObservableFuture get loader { - _$loaderAtom.context.enforceReadPolicy(_$loaderAtom); - _$loaderAtom.reportObserved(); + _$loaderAtom.reportRead(); return super.loader; } + bool _loaderIsInitialized = false; + @override set loader(ObservableFuture value) { - _$loaderAtom.context.conditionallyRunInAction(() { - super.loader = value; - _$loaderAtom.reportChanged(); - }, _$loaderAtom, name: '${_$loaderAtom.name}_set'); + _$loaderAtom.reportWrite( + value, + _loaderIsInitialized ? super.loader : null, + () { + super.loader = value; + _loaderIsInitialized = true; + }, + ); } - final _$_loadTodosAsyncAction = AsyncAction('_loadTodos'); + late final _$_loadTodosAsyncAction = AsyncAction( + 'TodoStoreBase._loadTodos', + context: context, + ); @override Future _loadTodos() { return _$_loadTodosAsyncAction.run(() => super._loadTodos()); } - final _$_TodoStoreActionController = ActionController(name: '_TodoStore'); + late final _$TodoStoreBaseActionController = ActionController( + name: 'TodoStoreBase', + context: context, + ); @override void toggleAll() { - final _$actionInfo = _$_TodoStoreActionController.startAction(); + final _$actionInfo = _$TodoStoreBaseActionController.startAction( + name: 'TodoStoreBase.toggleAll', + ); try { return super.toggleAll(); } finally { - _$_TodoStoreActionController.endAction(_$actionInfo); + _$TodoStoreBaseActionController.endAction(_$actionInfo); } } @override void clearCompleted() { - final _$actionInfo = _$_TodoStoreActionController.startAction(); + final _$actionInfo = _$TodoStoreBaseActionController.startAction( + name: 'TodoStoreBase.clearCompleted', + ); try { return super.clearCompleted(); } finally { - _$_TodoStoreActionController.endAction(_$actionInfo); + _$TodoStoreBaseActionController.endAction(_$actionInfo); } } + + @override + String toString() { + return ''' +filter: ${filter}, +loader: ${loader}, +pendingTodos: ${pendingTodos}, +completedTodos: ${completedTodos}, +hasCompletedTodos: ${hasCompletedTodos}, +hasPendingTodos: ${hasPendingTodos}, +numPending: ${numPending}, +numCompleted: ${numCompleted}, +visibleTodos: ${visibleTodos} + '''; + } } diff --git a/mobx/linux/.gitignore b/mobx/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/mobx/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/mobx/linux/CMakeLists.txt b/mobx/linux/CMakeLists.txt new file mode 100644 index 00000000..71e84acb --- /dev/null +++ b/mobx/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +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 "mobx_sample") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.mobx_sample") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +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() + +# 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() + +# 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_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# 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 +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# 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() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +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) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/mobx/linux/flutter/CMakeLists.txt b/mobx/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/mobx/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +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. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# 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/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter 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. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/mobx/linux/flutter/generated_plugin_registrant.cc b/mobx/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e71a16d2 --- /dev/null +++ b/mobx/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/mobx/linux/flutter/generated_plugin_registrant.h b/mobx/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/mobx/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/mobx/linux/flutter/generated_plugins.cmake b/mobx/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/mobx/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + 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}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/mobx/linux/runner/CMakeLists.txt b/mobx/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/mobx/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "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 +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/mobx/linux/runner/main.cc b/mobx/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/mobx/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/mobx/linux/runner/my_application.cc b/mobx/linux/runner/my_application.cc new file mode 100644 index 00000000..0b6f40d1 --- /dev/null +++ b/mobx/linux/runner/my_application.cc @@ -0,0 +1,130 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // 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 + // desktop). + // 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. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "mobx_sample"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "mobx_sample"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/mobx/linux/runner/my_application.h b/mobx/linux/runner/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/mobx/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/mobx/macos/.gitignore b/mobx/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/mobx/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/mobx/macos/Flutter/Flutter-Debug.xcconfig b/mobx/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/mobx/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/mobx/macos/Flutter/Flutter-Release.xcconfig b/mobx/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/mobx/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/mobx/macos/Flutter/GeneratedPluginRegistrant.swift b/mobx/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b8e2b22f --- /dev/null +++ b/mobx/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/mobx/macos/Podfile b/mobx/macos/Podfile new file mode 100644 index 00000000..29c8eb32 --- /dev/null +++ b/mobx/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/mobx/macos/Podfile.lock b/mobx/macos/Podfile.lock new file mode 100644 index 00000000..390b5331 --- /dev/null +++ b/mobx/macos/Podfile.lock @@ -0,0 +1,30 @@ +PODS: + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + +SPEC CHECKSUMS: + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + +PODFILE CHECKSUM: 7eb978b976557c8c1cd717d8185ec483fd090a82 + +COCOAPODS: 1.16.2 diff --git a/mobx/macos/Runner.xcodeproj/project.pbxproj b/mobx/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..cdd9ac24 --- /dev/null +++ b/mobx/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 87E488BBC18CE7864C4C407B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 035E91E51A94872019671456 /* Pods_Runner.framework */; }; + F9E2F6672CF45DDA09CEA7B1 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CC027EAE5F00C8083E5C07F4 /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 035E91E51A94872019671456 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0A2FF8AF12B8559BDF89874C /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 1988A0110B82B8D7ED59A1D1 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* mobx_sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = mobx_sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 4061F676840DB9B8D7AF1B0B /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + CC027EAE5F00C8083E5C07F4 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CDCE135CA4E73D7F584AEA72 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + F1F4C0431B128F96573A4B56 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + FC372711CA054B8FDB33E0C7 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F9E2F6672CF45DDA09CEA7B1 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 87E488BBC18CE7864C4C407B /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 756709D114E990443C3997DC /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* mobx_sample.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 756709D114E990443C3997DC /* Pods */ = { + isa = PBXGroup; + children = ( + CDCE135CA4E73D7F584AEA72 /* Pods-Runner.debug.xcconfig */, + F1F4C0431B128F96573A4B56 /* Pods-Runner.release.xcconfig */, + 1988A0110B82B8D7ED59A1D1 /* Pods-Runner.profile.xcconfig */, + 0A2FF8AF12B8559BDF89874C /* Pods-RunnerTests.debug.xcconfig */, + FC372711CA054B8FDB33E0C7 /* Pods-RunnerTests.release.xcconfig */, + 4061F676840DB9B8D7AF1B0B /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 035E91E51A94872019671456 /* Pods_Runner.framework */, + CC027EAE5F00C8083E5C07F4 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 98D75ED9ABCC905315ABCA33 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 34300F4A3A7C9FA90F3B19F8 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 3E614B60F41E87897E28382D /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* mobx_sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 34300F4A3A7C9FA90F3B19F8 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3E614B60F41E87897E28382D /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 98D75ED9ABCC905315ABCA33 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0A2FF8AF12B8559BDF89874C /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mobxSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mobx_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mobx_sample"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FC372711CA054B8FDB33E0C7 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mobxSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mobx_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mobx_sample"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 4061F676840DB9B8D7AF1B0B /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mobxSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mobx_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mobx_sample"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/mobx/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mobx/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/mobx/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/mobx/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/mobx/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..1b1d5b61 --- /dev/null +++ b/mobx/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobx/macos/Runner.xcworkspace/contents.xcworkspacedata b/mobx/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/mobx/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/mobx/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mobx/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/mobx/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/mobx/macos/Runner/AppDelegate.swift b/mobx/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/mobx/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/mobx/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/mobx/macos/Runner/Base.lproj/MainMenu.xib b/mobx/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/mobx/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobx/macos/Runner/Configs/AppInfo.xcconfig b/mobx/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..752facb4 --- /dev/null +++ b/mobx/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// 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 +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = mobx_sample + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.mobxSample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/mobx/macos/Runner/Configs/Debug.xcconfig b/mobx/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/mobx/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/mobx/macos/Runner/Configs/Release.xcconfig b/mobx/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/mobx/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/mobx/macos/Runner/Configs/Warnings.xcconfig b/mobx/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/mobx/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/mobx/macos/Runner/DebugProfile.entitlements b/mobx/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/mobx/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/mobx/macos/Runner/Info.plist b/mobx/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/mobx/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/mobx/macos/Runner/MainFlutterWindow.swift b/mobx/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/mobx/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/mobx/macos/Runner/Release.entitlements b/mobx/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/mobx/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/mobx/macos/RunnerTests/RunnerTests.swift b/mobx/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/mobx/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/mobx/package.json b/mobx/package.json deleted file mode 100644 index 0564f5ed..00000000 --- a/mobx/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "mobx_sample", - "version": "1.0.0", - "scripts": { - "generate": "flutter packages pub run build_runner watch --delete-conflicting-outputs" - } -} diff --git a/mobx/pubspec.yaml b/mobx/pubspec.yaml index 4fdbe688..01db0995 100644 --- a/mobx/pubspec.yaml +++ b/mobx/pubspec.yaml @@ -1,5 +1,8 @@ name: mobx_sample description: A new Flutter project. +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: "none" # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -8,18 +11,20 @@ description: A new Flutter project. # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ^3.8.1 dependencies: - mobx: ^0.4.0 - flutter_mobx: ^0.3.0 - provider: ^4.0.0 + mobx: + flutter_mobx: + provider: todos_repository_local_storage: path: ../todos_repository_local_storage todos_repository_core: @@ -28,28 +33,25 @@ dependencies: path: ../todos_app_core flutter: sdk: flutter - key_value_store_flutter: - key_value_store_web: shared_preferences: dev_dependencies: - mobx_codegen: ^0.4.0+1 - build_runner: ^1.7.3 + mobx_codegen: + build_runner: test: - flutter_driver: + flutter_lints: + integration_test: sdk: flutter integration_tests: path: ../integration_tests flutter_test: sdk: flutter - # For information on the generic Dart part of this file, see the # following page: https://www.dartlang.org/tools/pub/pubspec # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. diff --git a/mobx/test/home_screen_test.dart b/mobx/test/home_screen_test.dart index 7795c53e..54050402 100644 --- a/mobx/test/home_screen_test.dart +++ b/mobx/test/home_screen_test.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mobx/mobx.dart'; @@ -8,7 +7,6 @@ import 'package:mobx_sample/models/todo.dart'; import 'package:mobx_sample/stores/todo_store.dart'; import 'package:provider/provider.dart'; import 'package:todos_app_core/todos_app_core.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; import 'mock_repository.dart'; @@ -84,30 +82,18 @@ void main() { } class _TestWidget extends StatelessWidget { - final Widget child; - final TodosRepository repository; - final List todos; - - const _TestWidget({ - Key key, - this.child, - this.repository, - this.todos, - }) : super(key: key); - @override Widget build(BuildContext context) { return Provider( - create: (_) => TodoStore( - repository ?? MockRepository(), - todos: ObservableList.of(todos ?? defaultTodos()), - )..init(), + create: (_) => + TodoStore(MockRepository(), todos: ObservableList.of(defaultTodos())) + ..init(), child: MaterialApp( localizationsDelegates: [ MobxLocalizationsDelegate(), ArchSampleLocalizationsDelegate(), ], - home: child ?? const HomeScreen(), + home: const HomeScreen(), ), ); } @@ -124,10 +110,11 @@ List defaultTodos() { Matcher isChecked(bool isChecked) { return matchesSemantics( isChecked: isChecked, + hasTapAction: true, + hasFocusAction: true, hasCheckedState: true, + isFocusable: true, hasEnabledState: true, isEnabled: true, - isFocusable: true, - hasTapAction: true, ); } diff --git a/mobx/test/todo_store_test.dart b/mobx/test/todo_store_test.dart index 069c968b..4a1cf6ea 100644 --- a/mobx/test/todo_store_test.dart +++ b/mobx/test/todo_store_test.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:mobx/mobx.dart'; import 'package:mobx_sample/models/todo.dart'; import 'package:mobx_sample/stores/todo_store.dart'; @@ -26,9 +22,7 @@ void main() { ); final noPendingStore = TodoStore( MockRepository(), - todos: ObservableList.of([ - Todo(task: 'a', complete: true), - ]), + todos: ObservableList.of([Todo(task: 'a', complete: true)]), ); expect(hasPendingStore.hasPendingTodos, isTrue); @@ -45,9 +39,7 @@ void main() { ); final noCompletedStore = TodoStore( MockRepository(), - todos: ObservableList.of([ - Todo(task: 'a'), - ]), + todos: ObservableList.of([Todo(task: 'a')]), ); expect(hasCompletedStore.hasCompletedTodos, isTrue); diff --git a/mobx/test_driver/integration_test.dart b/mobx/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/mobx/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/mobx/test_driver/todo_app.dart b/mobx/test_driver/todo_app.dart deleted file mode 100644 index 09e1f4e4..00000000 --- a/mobx/test_driver/todo_app.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// This line imports the extension -import 'package:flutter_driver/driver_extension.dart'; -import 'package:mobx_sample/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/mobx/test_driver/todo_app_test.dart b/mobx/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/mobx/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/mobx/web/favicon.png b/mobx/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/mobx/web/favicon.png differ diff --git a/mobx/web/icons/Icon-192.png b/mobx/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/mobx/web/icons/Icon-192.png differ diff --git a/mobx/web/icons/Icon-512.png b/mobx/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/mobx/web/icons/Icon-512.png differ diff --git a/mobx/web/icons/Icon-maskable-192.png b/mobx/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/mobx/web/icons/Icon-maskable-192.png differ diff --git a/mobx/web/icons/Icon-maskable-512.png b/mobx/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/mobx/web/icons/Icon-maskable-512.png differ diff --git a/mobx/web/index.html b/mobx/web/index.html index 7454051f..48b94f9e 100644 --- a/mobx/web/index.html +++ b/mobx/web/index.html @@ -1,10 +1,38 @@ + + + - mobx + + + + + + + + + + + + + mobx_sample + - + diff --git a/mobx/web/manifest.json b/mobx/web/manifest.json new file mode 100644 index 00000000..c2e62c19 --- /dev/null +++ b/mobx/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "mobx_sample", + "short_name": "mobx_sample", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/mobx/windows/.gitignore b/mobx/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/mobx/windows/.gitignore @@ -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/ diff --git a/mobx/windows/CMakeLists.txt b/mobx/windows/CMakeLists.txt new file mode 100644 index 00000000..0e6d24b2 --- /dev/null +++ b/mobx/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(mobx_sample 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 "mobx_sample") + +# 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) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_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 "$") +# 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) diff --git a/mobx/windows/flutter/CMakeLists.txt b/mobx/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/mobx/windows/flutter/CMakeLists.txt @@ -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} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/mobx/windows/flutter/generated_plugin_registrant.cc b/mobx/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/mobx/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/mobx/windows/flutter/generated_plugin_registrant.h b/mobx/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/mobx/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/mobx/windows/flutter/generated_plugins.cmake b/mobx/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/mobx/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +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 $) + 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) diff --git a/mobx/windows/runner/CMakeLists.txt b/mobx/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/mobx/windows/runner/CMakeLists.txt @@ -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) diff --git a/mobx/windows/runner/Runner.rc b/mobx/windows/runner/Runner.rc new file mode 100644 index 00000000..0ac38590 --- /dev/null +++ b/mobx/windows/runner/Runner.rc @@ -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", "com.example" "\0" + VALUE "FileDescription", "mobx_sample" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "mobx_sample" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "mobx_sample.exe" "\0" + VALUE "ProductName", "mobx_sample" "\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 diff --git a/mobx/windows/runner/flutter_window.cpp b/mobx/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/mobx/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#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( + 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 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); +} diff --git a/mobx/windows/runner/flutter_window.h b/mobx/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/mobx/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#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_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/mobx/windows/runner/main.cpp b/mobx/windows/runner/main.cpp new file mode 100644 index 00000000..261a5c0d --- /dev/null +++ b/mobx/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 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"mobx_sample", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/mobx/windows/runner/resource.h b/mobx/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/mobx/windows/runner/resource.h @@ -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 diff --git a/mobx/windows/runner/resources/app_icon.ico b/mobx/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/mobx/windows/runner/resources/app_icon.ico differ diff --git a/mobx/windows/runner/runner.exe.manifest b/mobx/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/mobx/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/mobx/windows/runner/utils.cpp b/mobx/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/mobx/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +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 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::vector 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; +} diff --git a/mobx/windows/runner/utils.h b/mobx/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/mobx/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// 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, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/mobx/windows/runner/win32_window.cpp b/mobx/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/mobx/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#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(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( + 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(origin.x), + static_cast(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(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(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(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( + 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)); + } +} diff --git a/mobx/windows/runner/win32_window.h b/mobx/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/mobx/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// 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_ diff --git a/mvc/.flutter-plugins-dependencies b/mvc/.flutter-plugins-dependencies deleted file mode 100644 index b728d6fd..00000000 --- a/mvc/.flutter-plugins-dependencies +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"android":[{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":[]}],"date_created":"2020-02-10 11:24:16.829310","version":"1.14.7-pre.38"} \ No newline at end of file diff --git a/mvc/.gitignore b/mvc/.gitignore deleted file mode 100644 index 2ddde2a5..00000000 --- a/mvc/.gitignore +++ /dev/null @@ -1,73 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# 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 -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.packages -.pub-cache/ -.pub/ -/build/ - -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/mvc/.metadata b/mvc/.metadata deleted file mode 100644 index 1b5cec02..00000000 --- a/mvc/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 27321ebbad34b0a3fafe99fac037102196d655ff - channel: stable - -project_type: app diff --git a/mvc/README.md b/mvc/README.md deleted file mode 100644 index a71634b1..00000000 --- a/mvc/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# MVC -MVC was first conceived some forty years ago by a visiting scientist at Xerox Palo Alto Research Laboratory (PARC) in California by the name of, Trygve Reenskaug. Most of the more recent design patterns are reflections of this original. It is hoped, this sample app will successfully convey how one might implement MVC when developing software. - -Note, the publicly available package, [mvc_pattern](https://pub.dartlang.org/packages/mvc_pattern), is used to demonstrate the Model-View-Controller design pattern in this particular architecture pattern sample. - -##### The MVC Design Pattern and Other Architectures -Like other design patterns, MVC aims to decouple major aspects generally found in software applications. In the case of MVC, it is three particular features: the Interface, the Event Handling, and the Data. This will generally allow for more efficient and modular code, more code reuse and parallel development. Like most things, it ‘makes life easier’ if you break things down into its separate working parts. The bigger the software application; the bigger the importance to implement such design patterns. - -## MVC in a nutshell: -* Controller responses to system and user events--controlling what's displayed. -* View is concerned primarily with 'how' it's displayed. -* Model is the Controller’s data source for what's displayed or not. - -In many MVC arrangements, the View knows how to ‘talk to’ the Controller, and the Controller knows how to ‘talk to’ the Model. However, the View and the Model each have no idea of the other’s existence. -![pac pattern](https://camo.githubusercontent.com/a5b152ecc2f2b96b8019941a7382f47f4ac4c2b6/68747470733a2f2f692e696d6775722e636f6d2f723443317932382e706e67) - -(View calls Controller functions; Controller calls Model functions.) - -Such a characteristic allows one, for example, to switch out and put in a different Model with little consequence. The 'new' Model need only conform to the API requirements so the Controller can ‘talk to’ it correctly. Conceivably, in turn, a 'new' View could be introduced aligned with the same functions names (same api) so it too correctly 'talks to' the Controller. Each is decoupled from the other two to such a degree that modification of any one component should not adversely effect the other two. - -However, the 'lines of communication' can be changed depending on the application's particular needs, but the 'separation of responsibilities' generally remain the same. - -![mvc pattern](https://user-images.githubusercontent.com/32497443/47087587-6614ed00-d1ea-11e8-8fc3-ced0ac6af12a.jpg) -![controllermodels](https://user-images.githubusercontent.com/32497443/47764873-a457e500-dc9d-11e8-8d89-2f1b8521335e.jpeg) -## Flutter and MVC -With the understanding that ‘the Interface’, 'the event handling' and ‘the data’ are now to be separated when using this design pattern, it's currently concluded in this MVC package that the **build()** function found in a typical **Stateful** or **Stateless** Widget will represent 'the View', while anything 'called' inside that function or any 'events' occurring within that function will execute code typically found in 'the Controller.' - -In this sample app, for example, the add_edit_screen.dart file involved in adding or editing a 'ToDo' item, is highlighted below where the 'Controller' is referenced. Most references are found within the **build()** function. If, for example, the user presses a button to add or save a 'ToDo' item, the Controller is called upon (see last arrow) to repsond to the event. -![add_edit_screen](https://user-images.githubusercontent.com/32497443/47756814-fedf4a00-dc79-11e8-95b5-13f3b864ce1c.jpg) -## Begin Your MVC App -In the screenshot below, you see the implementation of the MVC library package. The class, MVCApp, extends the class, AppMVC, found in the MVC library package. In this one screenshot, you can also see both the Controller and the View. The class, MVCApp, instantiates the Controller as a parameter to its superclass's constructor while the View is essentially the Widget returned from the **build()** function. -![02mvcapp](https://user-images.githubusercontent.com/32497443/47758418-559c5200-dc81-11e8-961e-1a18548216c4.jpg) -In the main.dart file, you see the usual **runApp()** function: -![01main dart](https://user-images.githubusercontent.com/32497443/47758766-db6ccd00-dc82-11e8-9f83-29c57ad73aa2.jpg) -## The Controller -Looking at just the first few lines of the Controller, you can see a lot is happening here. For example, you can see the [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) in the form of a list of import statements taking in only what the Controller depends on to fulfill its function. And so, it's here where the Model is instantiated as it is only here where it is readily used. The View has no knowledge of the Model nor does it need to at this point. -![controller](https://user-images.githubusercontent.com/32497443/48212521-c5799f00-e349-11e8-9280-e25bb49086a7.png) -However, note the variable, model, is static and is not 'library-private' (no leading underscore). This allows the developer, if they wish, to externally reference the Model so to access its public functions and properties. Depending on the circumstances, this may be desired. At this point, the developer has that option. Of course, adding an underscore would then change those 'lines of communication'. - -The 'VisibiltyFilter' is concerned with 'what' type of 'ToDo' items are displayed (what is displayed) at any one time in this 'ToDo' app. As it happens, this concern is also one of the responsibilities of the Controller, and so this 'filter' is implemented only in the Controller. - -Finally, note the Controller uses a factory constructor. This allows for the Controller to be instantiated once, but referenced everywhere if need be. However, the developer has the option to use a getter instead to access the Controller. Again, doing so allows for easy access to the Controller throughout the rest of the application: -![concon](https://user-images.githubusercontent.com/32497443/47794282-8a96bc00-dcf6-11e8-8a7e-3a602649e753.jpg) -## The Controller and its Model -The Controller is fully listed below, and you can see highlighted where the Model is called to retrieve, save and update the data source (whatever that data source may be). The View nor the Controller 'knows' what type of data source it is, or what type of database the data resides in. They don't need to. The Model takes care of that. -![controller](https://user-images.githubusercontent.com/32497443/48216483-d5e24780-e352-11e8-8e2c-47e12fac8ba6.png) -##### What's in a name? (or API?) -Looking closely at the code, you can see the Controller's public functions have names that don't always match the Model functions they, in turn, call. This is part of the decoupling that's possible with this design pattern. For instanct, the View need only know the names of the Controller's public functions and public fields (the Controller's API). Retain the Controller's API (In other words, keep those public function names consistant over time), and the Model is able to be changed more freely. Only the Controller would then have to address any Model changes. It's no concern to any other part of the application thus encouraging modular coding. -##### How about the Model? -Looking at the Model in this sample (see below), and you can see that it itself has its own Model to work with---unbeknownst to the rest of the application. For this app, this Model serves to 'convert' the data format from its own data source to a format eventually used by the View. -##### I Scooped the Scoped Model! -For full disclosure, I may have taken liberties as I chose to abscond the 'Model' and 'localization' code from Brian Egan's own 'Scoped Model' contribution to possibly accentuate my own. Again, to demonstrate how a MVC's Model, at times, may be used 'to convert' a data source to a format suitable to own its application. -![model](https://user-images.githubusercontent.com/32497443/47763415-0234fe80-dc97-11e8-9967-c7a5cef11e32.jpg) -##### Map the Data - We're just using a Map for the View instead of a Middle man class, like a TodoViewModel. In this 'ToDo' app sample, the data is displayed using Dart's own [Map](https://www.dartlang.org/guides/language/language-tour#maps) built-in type (see below). However, the 'repository' offered by all of us contributing to this [Flutter Architecture Samples](http://fluttersamples.com/) project does not. Instead, it uses the class, [TodoEntity](https://github.com/brianegan/flutter_architecture_samples/blob/master/todos_repository/lib/src/todo_entity.dart). I decided to demonstrate this 'conduit' role sometimes play by a Model. Of course, the rest of the sample app is unaware of the conversion therefore required. -![add_edit_screen2](https://user-images.githubusercontent.com/32497443/47791412-08a39480-dcf0-11e8-864c-69c0725e625d.jpg) -##### The Model is the Conduit -Again, in this particular 'ToDo' app sample, the MVC implementation has the Model play the role of 'conduit.' It lies between the data repository supplied by the makers of this project and the rest of this application. -![conroller2models](https://user-images.githubusercontent.com/32497443/47765618-30b7d700-dca1-11e8-98b0-2d1ee2c5a112.jpeg) -Looking at the class, TodoListModel, which is called by our Model class, you can see it is concerned with that data repository. It imports only that which it depends on, and changes the 'format' of the data where appropriate. -![todo_list_model](https://user-images.githubusercontent.com/32497443/47764056-d7987500-dc99-11e8-90d0-e62b60546993.jpg) -In turn, the class, Todo, is called by the class, TodoListModel. It mirrors the project's class, TodoEntity, and is used 'to bridge' information between those two classes. Again, this modular approach hides this fact from the rest of the application. -![models](https://user-images.githubusercontent.com/32497443/47764337-10851980-dc9b-11e8-8e89-61d009f5cd0d.jpg) -```dart -``` - - -Further information on the MVC package can be found in the article, [‘Flutter + MVC at Last!’](https://medium.com/p/275a0dc1e730/) -[![online article](https://user-images.githubusercontent.com/32497443/47087365-c9524f80-d1e9-11e8-85e5-6c8bbabb18cc.png)](https://medium.com/flutter-community/flutter-mvc-at-last-275a0dc1e730) - -[Repository (GitHub)](https://github.com/AndriousSolutions/mvc_pattern) - -[API Docs](https://pub.dartlang.org/documentation/mvc_pattern/latest/mvc_pattern/mvc_pattern-library.html) diff --git a/mvc/android/.gitignore b/mvc/android/.gitignore deleted file mode 100644 index bc2100d8..00000000 --- a/mvc/android/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java diff --git a/mvc/android/app/build.gradle b/mvc/android/app/build.gradle deleted file mode 100644 index 7b8ed369..00000000 --- a/mvc/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.mvc" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/mvc/android/app/src/debug/AndroidManifest.xml b/mvc/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index eb9a5f75..00000000 --- a/mvc/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/mvc/android/app/src/main/AndroidManifest.xml b/mvc/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 9d2c10b9..00000000 --- a/mvc/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - diff --git a/mvc/android/app/src/main/kotlin/com/example/mvc/MainActivity.kt b/mvc/android/app/src/main/kotlin/com/example/mvc/MainActivity.kt deleted file mode 100644 index b40a40c6..00000000 --- a/mvc/android/app/src/main/kotlin/com/example/mvc/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.mvc - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/mvc/android/app/src/main/res/drawable/launch_background.xml b/mvc/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/mvc/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/mvc/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/mvc/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index a3f285f9..00000000 Binary files a/mvc/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/mvc/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/mvc/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 5e6f3ac6..00000000 Binary files a/mvc/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/mvc/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/mvc/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 144d60be..00000000 Binary files a/mvc/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/mvc/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/mvc/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index deafae2d..00000000 Binary files a/mvc/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/mvc/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/mvc/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index d5614ac8..00000000 Binary files a/mvc/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/mvc/android/app/src/main/res/values/styles.xml b/mvc/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 00fa4417..00000000 --- a/mvc/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/mvc/android/app/src/profile/AndroidManifest.xml b/mvc/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index eb9a5f75..00000000 --- a/mvc/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/mvc/android/build.gradle b/mvc/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/mvc/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/mvc/android/gradle.properties b/mvc/android/gradle.properties deleted file mode 100644 index 38c8d454..00000000 --- a/mvc/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true -android.useAndroidX=true -android.enableJetifier=true diff --git a/mvc/android/gradle/wrapper/gradle-wrapper.properties b/mvc/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 296b146b..00000000 --- a/mvc/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/mvc/android/settings.gradle b/mvc/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/mvc/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/mvc/ios/.gitignore b/mvc/ios/.gitignore deleted file mode 100644 index e96ef602..00000000 --- a/mvc/ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/mvc/ios/Flutter/AppFrameworkInfo.plist b/mvc/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6b4c0f78..00000000 --- a/mvc/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/mvc/ios/Flutter/Debug.xcconfig b/mvc/ios/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba11..00000000 --- a/mvc/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/mvc/ios/Flutter/Release.xcconfig b/mvc/ios/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340..00000000 --- a/mvc/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/mvc/ios/Podfile b/mvc/ios/Podfile deleted file mode 100644 index b30a428b..00000000 --- a/mvc/ios/Podfile +++ /dev/null @@ -1,90 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '9.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; - end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end - end - generated_key_values -end - -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; - - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' - - # Plugin Pods - - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') - end -end - -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - -post_install do |installer| - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end - end -end diff --git a/mvc/ios/Runner.xcodeproj/project.pbxproj b/mvc/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index f4be4884..00000000 --- a/mvc/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,518 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.mvc; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.mvc; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.mvc; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/mvc/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mvc/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/mvc/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/mvc/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/mvc/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140cf..00000000 --- a/mvc/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mvc/ios/Runner.xcworkspace/contents.xcworkspacedata b/mvc/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/mvc/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/mvc/ios/Runner/AppDelegate.swift b/mvc/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a..00000000 --- a/mvc/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d22f10b2..00000000 --- a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 980e5ad6..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index fd870289..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 75e84cd1..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 03ab8a84..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index a03431cb..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index f47613ee..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 7f2230a9..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 42315c6d..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index f9882cc0..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 45537513..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 6360ea17..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 152d5e12..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 310b0b8f..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 092b7bfe..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2f..00000000 --- a/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/mvc/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -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. \ No newline at end of file diff --git a/mvc/ios/Runner/Base.lproj/LaunchScreen.storyboard b/mvc/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/mvc/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mvc/ios/Runner/Base.lproj/Main.storyboard b/mvc/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/mvc/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mvc/ios/Runner/Info.plist b/mvc/ios/Runner/Info.plist deleted file mode 100644 index cbd0405a..00000000 --- a/mvc/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - mvc - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/mvc/ios/Runner/Runner-Bridging-Header.h b/mvc/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 7335fdf9..00000000 --- a/mvc/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file diff --git a/mvc/lib/main.dart b/mvc/lib/main.dart deleted file mode 100644 index 59f0710d..00000000 --- a/mvc/lib/main.dart +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/material.dart'; - -import 'package:mvc/src/App.dart'; - -void main() { - runApp(MVCApp()); -} diff --git a/mvc/lib/src/App.dart b/mvc/lib/src/App.dart deleted file mode 100644 index 9d7d32b2..00000000 --- a/mvc/lib/src/App.dart +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:scoped_model_sample/localization.dart'; - -import 'package:mvc/src/screens/add_edit_screen.dart'; -import 'package:mvc/src/screens/home_screen.dart'; - -import 'package:mvc_pattern/mvc_pattern.dart'; -import 'package:mvc/src/Controller.dart'; - -class MVCApp extends AppMVC { - MVCApp({Key key}) : super(con: _controller, key: key); - - /// An external reference to the Controller if you wish. -gp - static final Con _controller = Con(); - - static MaterialApp _app; - - static String get title => _app.title.toString(); - - @override - Widget build(BuildContext context) { - _app = MaterialApp( - title: 'mvc example', - theme: ArchSampleTheme.theme, - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - ScopedModelLocalizationsDelegate(), - ], - routes: { - ArchSampleRoutes.home: (context) => HomeScreen(), - ArchSampleRoutes.addTodo: (context) => AddEditScreen(), - }, - ); - return _app; - } -} diff --git a/mvc/lib/src/Controller.dart b/mvc/lib/src/Controller.dart deleted file mode 100644 index 31e3ce44..00000000 --- a/mvc/lib/src/Controller.dart +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async' show Future; -import 'package:mvc_pattern/mvc_pattern.dart' show ControllerMVC; - -import 'package:mvc/src/todo_list_model.dart' show VisibilityFilter; -import 'package:mvc/src/Model.dart' show Model; - -import 'package:mvc/src/App.dart' show MVCApp; - -/// The Controller answers & responses to 'the events' while the Model execute 'the rules' and manipulates data. -class Con extends ControllerMVC { - factory Con() { - return _this ??= Con._(); - } - static Con _this; - - Con._(); - - /// Allow for easy access to 'the Controller' throughout the application. - static Con get con => _this; - - static final model = Model(); - - static VisibilityFilter get activeFilter => model.activeFilter; - static set activeFilter(VisibilityFilter filter) => - model.activeFilter = filter; - - static List> get todos => model.todos; - - static bool get isLoading => model.isLoading; - - String get title => MVCApp.title; - - /// Called by the View. - void init() => loadData(); - - Future loadData() async { - var load = await model.loadTodos(); - // In this case, it is the Controller that decides to 'refresh' the View. - refresh(); - return load; - } - - static List get filteredTodos => model.filteredTodos; - - void clear() { - /// Only the Model 'knows' what it done when there's a 'clear' message issued. - model.clearCompleted(); - // In this case, it is the Controller that decides to 'refresh' the View. - refresh(); - } - - void toggle() { - model.toggleAll(); - // In this case, it is the Controller that decides to 'refresh' the View. - refresh(); - } - - void checked(Map data) { - /// The Model has the 'business rules' that fire when an item is checked. - model.checkCompleted(data); - // In this case, it is the Controller that decides to 'refresh' the View. - refresh(); - } - - void updateTodo(Map data) { - model.updateTodo(data); - // In this case, it is the Controller that decides to 'refresh' the View. - refresh(); - } - - void remove(Map dataItem) { - model.removeTodo(dataItem); - // In this case, it is the Controller that decides to 'refresh' the View. - refresh(); - } - - void undo(Map dataItem) { - /// The Model 'knows' how to undo a remove of an item. - model.undoRemove(dataItem); - // In this case, it is the Controller that decides to 'refresh' the View. - refresh(); - } - - void update(Map dataItem) { - /// Updates the database. Either add a new data item or updating an existing one. - model.update(dataItem); - // In this case, it is the Controller that decides to 'refresh' the View. - refresh(); - } - - void addTodo(Map data) { - model.addTodo(data); - // In this case, it is the Controller that decides to 'refresh' the View. - refresh(); - } - - Map todoById(String id) { - return model.todoById(id); - } -} diff --git a/mvc/lib/src/Model.dart b/mvc/lib/src/Model.dart deleted file mode 100644 index 4867f016..00000000 --- a/mvc/lib/src/Model.dart +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async' show Future; - -/// It is this Model that 'knows of' this class. -/// This is to demonstrate the modular approach and 'separation of responsibilities' -import 'package:mvc/src/todo_list_model.dart' - show To, TodoListModel, VisibilityFilter; - -class Model { - final todoModel = TodoListModel(); - - VisibilityFilter get activeFilter => todoModel.activeFilter; - - set activeFilter(VisibilityFilter filter) { - todoModel.activeFilter = filter; - } - - List get todos => todoModel.todos.map(To.map).toList(); - - bool get isLoading => todoModel.isLoading; - - Future loadTodos() { - return todoModel.loadTodos(); - } - - List get filteredTodos => todoModel.filteredTodos.map(To.map).toList(); - - void clearCompleted() { - todoModel.clearCompleted(); - } - - void toggleAll() { - todoModel.toggleAll(); - } - - void removeTodo(Map data) { - todoModel.removeTodo(To.todo(data)); - } - - void undoRemove(Map data) { - data['id'] = null; - update(data); - } - - void update(Map data) { - if (data['id'] == null) { - todoModel.addTodo(To.todo(data)); - } else { - todoModel.updateTodo(To.todo(data)); - } - } - - void checkCompleted(Map data) { - /// The model 'knows' which field is involved when an item is checked. - data['complete'] = !data['complete']; - updateTodo(data); - } - - void updateTodo(Map data) { - todoModel.updateTodo(To.todo(data)); - } - - void addTodo(Map data) { - todoModel.addTodo(To.todo(data)); - } - - Map todoById(String id) { - return To.map(todoModel.todoById(id)).cast(); - } -} diff --git a/mvc/lib/src/models.dart b/mvc/lib/src/models.dart deleted file mode 100644 index e7b2e243..00000000 --- a/mvc/lib/src/models.dart +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:todos_app_core/todos_app_core.dart' show Uuid; -import 'package:todos_repository_core/todos_repository_core.dart' - show TodoEntity; - -enum AppTab { todos, stats } - -enum ExtraAction { toggleAllComplete, clearCompleted } - -class Todo { - final bool complete; - final String id; - final String note; - final String task; - - Todo(this.task, {this.complete = false, this.note = '', String id}) - : id = id ?? Uuid().generateV4(); - - @override - int get hashCode => - complete.hashCode ^ task.hashCode ^ note.hashCode ^ id.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is Todo && - runtimeType == other.runtimeType && - complete == other.complete && - task == other.task && - note == other.note && - id == other.id; - - @override - String toString() { - return 'Todo{complete: $complete, task: $task, note: $note, id: $id}'; - } - - TodoEntity toEntity() { - return TodoEntity(task, id, note, complete); - } - - static Todo fromEntity(TodoEntity entity) { - return Todo( - entity.task, - complete: entity.complete ?? false, - note: entity.note, - id: entity.id, - ); - } - - Todo copy({String task, bool complete, String note, String id}) { - return Todo( - task ?? this.task, - complete: complete ?? this.complete, - note: note ?? this.note, - id: id ?? this.id, - ); - } -} diff --git a/mvc/lib/src/screens/add_edit_screen.dart b/mvc/lib/src/screens/add_edit_screen.dart deleted file mode 100644 index a63eb74c..00000000 --- a/mvc/lib/src/screens/add_edit_screen.dart +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async' show Future; -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart' - show ArchSampleKeys, ArchSampleLocalizations; - -/// The 'View' should know nothing of the 'Model.' -/// The 'View' only knows how to 'talk to' the Controller. -import 'package:mvc/src/Controller.dart' show Con; - -class AddEditScreen extends StatefulWidget { - final String todoId; - - AddEditScreen({ - Key key, - this.todoId, - }) : super(key: key ?? ArchSampleKeys.addTodoScreen); - - @override - _AddEditScreenState createState() => _AddEditScreenState(); -} - -class _AddEditScreenState extends State { - static final GlobalKey formKey = GlobalKey(); - - final Con _con = Con.con; - String _task; - String _note; - - @override - Widget build(BuildContext context) { - /// Return the 'universally recognized' Map object. - /// The data will only be known through the use of Map objects. - final todo = _con.todoById(widget.todoId); - - return Scaffold( - appBar: AppBar( - title: Text(isEditing - ? ArchSampleLocalizations.of(context).editTodo - : ArchSampleLocalizations.of(context).addTodo), - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: Form( - key: formKey, - autovalidate: false, - onWillPop: () { - return Future(() => true); - }, - child: ListView( - children: [ - TextFormField( - initialValue: todo['task'] ?? '', - key: ArchSampleKeys.taskField, - autofocus: isEditing ? false : true, - style: Theme.of(context).textTheme.headline, - decoration: InputDecoration( - hintText: ArchSampleLocalizations.of(context).newTodoHint), - validator: (val) => val.trim().isEmpty - ? ArchSampleLocalizations.of(context).emptyTodoError - : null, - onSaved: (value) => _task = value, - ), - TextFormField( - initialValue: todo['note'] ?? '', - key: ArchSampleKeys.noteField, - maxLines: 10, - style: Theme.of(context).textTheme.subhead, - decoration: InputDecoration( - hintText: ArchSampleLocalizations.of(context).notesHint, - ), - onSaved: (value) => _note = value, - ) - ], - ), - ), - ), - floatingActionButton: FloatingActionButton( - key: - isEditing ? ArchSampleKeys.saveTodoFab : ArchSampleKeys.saveNewTodo, - tooltip: isEditing - ? ArchSampleLocalizations.of(context).saveChanges - : ArchSampleLocalizations.of(context).addTodo, - child: Icon(isEditing ? Icons.check : Icons.add), - onPressed: () { - final form = formKey.currentState; - if (form.validate()) { - form.save(); - todo['task'] = _task; - todo['note'] = _note; - if (isEditing) { - _con.update(todo); - } else { - _con.addTodo(todo); - } - Navigator.pop(context, todo); - } - }, - ), - ); - } - - bool get isEditing => widget.todoId != null; -} diff --git a/mvc/lib/src/screens/detail_screen.dart b/mvc/lib/src/screens/detail_screen.dart deleted file mode 100644 index 231889d2..00000000 --- a/mvc/lib/src/screens/detail_screen.dart +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart' show required; -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart' - show ArchSampleKeys, ArchSampleLocalizations; - -import 'package:mvc/src/screens/add_edit_screen.dart' show AddEditScreen; - -import 'package:mvc/src/Controller.dart' show Con; - -class DetailScreen extends StatelessWidget { - final String todoId; - - final Con con = Con.con; - - DetailScreen({ - @required this.todoId, - }) : super(key: ArchSampleKeys.todoDetailsScreen); - - @override - Widget build(BuildContext context) { - Map todo = con.todoById(todoId); - return Scaffold( - appBar: AppBar( - title: Text(ArchSampleLocalizations.of(context).todoDetails), - actions: [ - IconButton( - key: ArchSampleKeys.deleteTodoButton, - tooltip: ArchSampleLocalizations.of(context).deleteTodo, - icon: Icon(Icons.delete), - onPressed: () { - con.remove(todo); - Navigator.pop(context, todo); - }, - ) - ], - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: ListView( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(right: 8.0), - child: Checkbox( - value: todo['complete'], - key: ArchSampleKeys.detailsTodoItemCheckbox, - onChanged: (complete) { - con.checked(todo); - }, - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), - child: Text( - todo['task'], - key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, - ), - ), - Text( - todo['note'], - key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) - ], - ), - ), - ], - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - tooltip: ArchSampleLocalizations.of(context).editTodo, - child: Icon(Icons.edit), - key: ArchSampleKeys.editTodoFab, - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) { - return AddEditScreen( - todoId: todoId, - key: ArchSampleKeys.editTodoScreen, - ); - }, - ), - ); - }, - ), - ); - } -} diff --git a/mvc/lib/src/screens/home_screen.dart b/mvc/lib/src/screens/home_screen.dart deleted file mode 100644 index 96f31926..00000000 --- a/mvc/lib/src/screens/home_screen.dart +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart' - show ArchSampleKeys, ArchSampleLocalizations, ArchSampleRoutes; - -import 'package:mvc/src/models.dart' show AppTab; -import 'package:mvc/src/widgets/extra_actions_button.dart' - show ExtraActionsButton; -import 'package:mvc/src/widgets/filter_button.dart' show FilterButton; -import 'package:mvc/src/widgets/stats_counter.dart' show StatsCounter; -import 'package:mvc/src/widgets/todo_list.dart' show TodoList; - -import 'package:mvc/src/Controller.dart' show Con; - -class HomeScreen extends StatefulWidget { - @protected - @override - State createState() => HomeView(); -} - -class HomeView extends State { - AppTab _activeTab = AppTab.todos; - - final Con _con = Con.con; - - @protected - @override - void initState() { - super.initState(); - - /// Calls the Controller when this one-time 'init' event occurs. - /// Not revealing the 'business logic' that then fires inside. - _con.init(); - } - - @protected - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - /// The View need not know nor care what the title is. The Controller does. - title: Text(_con.title), - actions: [ - FilterButton(isActive: _activeTab == AppTab.todos), - ExtraActionsButton() - ], - ), - body: _activeTab == AppTab.todos ? TodoList() : StatsCounter(), - floatingActionButton: FloatingActionButton( - key: ArchSampleKeys.addTodoFab, - onPressed: () { - Navigator.pushNamed(context, ArchSampleRoutes.addTodo); - }, - child: Icon(Icons.add), - tooltip: ArchSampleLocalizations.of(context).addTodo, - ), - bottomNavigationBar: BottomNavigationBar( - key: ArchSampleKeys.tabs, - currentIndex: AppTab.values.indexOf(_activeTab), - onTap: (index) { - setState(() { - _activeTab = AppTab.values[index]; - }); - }, - items: AppTab.values.map((tab) { - return BottomNavigationBarItem( - icon: Icon( - tab == AppTab.todos ? Icons.list : Icons.show_chart, - key: tab == AppTab.stats - ? ArchSampleKeys.statsTab - : ArchSampleKeys.todoTab, - ), - title: Text( - tab == AppTab.stats - ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos, - ), - ); - }).toList(), - ), - ); - } -} diff --git a/mvc/lib/src/todo_list_model.dart b/mvc/lib/src/todo_list_model.dart deleted file mode 100644 index 3863533b..00000000 --- a/mvc/lib/src/todo_list_model.dart +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:path_provider/path_provider.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; -import 'package:mvc/src/models.dart'; - -class TodoListModel { - TodoListModel({TodosRepository repo, VisibilityFilter activeFilter}) - : _activeFilter = activeFilter ?? VisibilityFilter.all { - /// The rest of the app need not know of its existence. - repository = repo ?? - LocalStorageRepository( - localStorage: const FileStorage( - 'mvc_app', - getApplicationDocumentsDirectory, - ), - ); - } - TodosRepository repository; - - VisibilityFilter get activeFilter => _activeFilter; - set activeFilter(VisibilityFilter filter) => _activeFilter = filter; - VisibilityFilter _activeFilter; - - List get todos => _todos.toList(); - List _todos = []; - - bool get isLoading => _isLoading; - bool _isLoading = false; - - /// Loads remote data - Future loadTodos() { - _isLoading = true; - return repository.loadTodos().then((loadedTodos) { - _todos = loadedTodos.map(Todo.fromEntity).toList(); - _isLoading = false; - }).catchError((err) { - _isLoading = false; - _todos = []; - }); - } - - List get filteredTodos => _todos.where((todo) { - switch (activeFilter) { - case VisibilityFilter.active: - return !todo.complete; - case VisibilityFilter.completed: - return todo.complete; - case VisibilityFilter.all: - default: - return true; - } - }).toList(); - - void clearCompleted() { - _todos.removeWhere((todo) => todo.complete); - _uploadItems(); - } - - void toggleAll() { - var allComplete = todos.every((todo) => todo.complete); - _todos = _todos.map((todo) => todo.copy(complete: !allComplete)).toList(); - _uploadItems(); - } - - /// updates by replacing the item with the same id by the parameter - void updateTodo(Todo todo) { - assert(todo != null); - assert(todo.id != null); - var oldTodo = _todos.firstWhere((it) => it.id == todo.id); - var replaceIndex = _todos.indexOf(oldTodo); - _todos.replaceRange(replaceIndex, replaceIndex + 1, [todo]); - _uploadItems(); - } - - void removeTodo(Todo todo) { - _todos.removeWhere((it) => it.id == todo.id); - _uploadItems(); - } - - void addTodo(Todo todo) { - _todos.add(todo); - _uploadItems(); - } - - void _uploadItems() { - repository.saveTodos(_todos.map((it) => it.toEntity()).toList()); - } - - Todo todoById(String id) { - return _todos.firstWhere((it) => it.id == id, orElse: () => null); - } -} - -enum VisibilityFilter { all, active, completed } - -class To { - /// Convert from a Map object - static Todo todo(Map data) { - return Todo(data['task'], - complete: data['complete'], note: data['note'], id: data['id']); - } - - /// Used to 'interface' with the View in the MVC design pattern. - static Map map(Todo obj) => { - 'task': obj == null ? '' : obj.task, - 'note': obj == null ? '' : obj.note, - 'complete': obj == null ? false : obj.complete, - 'id': obj == null ? null : obj.id, - }; -} diff --git a/mvc/lib/src/widgets/extra_actions_button.dart b/mvc/lib/src/widgets/extra_actions_button.dart deleted file mode 100644 index e4487374..00000000 --- a/mvc/lib/src/widgets/extra_actions_button.dart +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:scoped_model_sample/models.dart'; - -import 'package:mvc/src/Controller.dart'; - -class ExtraActionsButton extends StatelessWidget { - ExtraActionsButton({ - Key key, - }) : super(key: key); - - final con = Con.con; - - @override - Widget build(BuildContext context) { - return PopupMenuButton( - key: ArchSampleKeys.extraActionsButton, - onSelected: (action) { - if (action == ExtraAction.toggleAllComplete) { - con.toggle(); - } else if (action == ExtraAction.clearCompleted) { - /// The View nor the Conttoller need not know what's involved. - con.clear(); - } - }, - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - key: ArchSampleKeys.toggleAll, - value: ExtraAction.toggleAllComplete, - child: Text(Con.todos.any((it) => !it['complete']) - ? ArchSampleLocalizations.of(context).markAllComplete - : ArchSampleLocalizations.of(context).markAllIncomplete), - ), - PopupMenuItem( - key: ArchSampleKeys.clearCompleted, - value: ExtraAction.clearCompleted, - child: Text(ArchSampleLocalizations.of(context).clearCompleted), - ), - ], - ); - } -} diff --git a/mvc/lib/src/widgets/filter_button.dart b/mvc/lib/src/widgets/filter_button.dart deleted file mode 100644 index 25a504b1..00000000 --- a/mvc/lib/src/widgets/filter_button.dart +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:mvc/src/todo_list_model.dart'; -import 'package:mvc/src/Controller.dart'; - -class FilterButton extends StatelessWidget { - final bool isActive; - - FilterButton({this.isActive, Key key}) : super(key: key); - - final con = Con.con; - - @override - Widget build(BuildContext context) { -// var model = TodoListModel.of(context, rebuildOnChange: true); - return AnimatedOpacity( - opacity: isActive ? 1.0 : 0.0, - duration: Duration(milliseconds: 150), - child: PopupMenuButton( - key: ArchSampleKeys.filterButton, - tooltip: ArchSampleLocalizations.of(context).filterTodos, - onSelected: (filter) { - Con.activeFilter = filter; - con.refresh(); - }, - itemBuilder: (BuildContext context) => _items(context), - icon: Icon(Icons.filter_list), - ), - ); - } - - List> _items(BuildContext context) { - final activeStyle = Theme.of(context) - .textTheme - .body1 - .copyWith(color: Theme.of(context).accentColor); - final defaultStyle = Theme.of(context).textTheme.body1; - - return [ - PopupMenuItem( - key: ArchSampleKeys.allFilter, - value: VisibilityFilter.all, - child: Text( - ArchSampleLocalizations.of(context).showAll, - style: Con.activeFilter == VisibilityFilter.all - ? activeStyle - : defaultStyle, - ), - ), - PopupMenuItem( - key: ArchSampleKeys.activeFilter, - value: VisibilityFilter.active, - child: Text( - ArchSampleLocalizations.of(context).showActive, - style: Con.activeFilter == VisibilityFilter.active - ? activeStyle - : defaultStyle, - ), - ), - PopupMenuItem( - key: ArchSampleKeys.completedFilter, - value: VisibilityFilter.completed, - child: Text( - ArchSampleLocalizations.of(context).showCompleted, - style: Con.activeFilter == VisibilityFilter.completed - ? activeStyle - : defaultStyle, - ), - ), - ]; - } -} diff --git a/mvc/lib/src/widgets/stats_counter.dart b/mvc/lib/src/widgets/stats_counter.dart deleted file mode 100644 index 5dab115b..00000000 --- a/mvc/lib/src/widgets/stats_counter.dart +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:mvc/src/Controller.dart'; - -class StatsCounter extends StatelessWidget { - StatsCounter() : super(key: ArchSampleKeys.statsCounter); - - bool isActive(Map todo) => !todo['complete']; - - bool isCompleted(Map todo) => todo['complete']; - - @override - Widget build(BuildContext context) { - var numCompleted = Con.model.todos.where(isCompleted).toList().length; - var numActive = Con.todos.where(isActive).toList().length; - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '$numCompleted', - key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '$numActive', - key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, - ), - ) - ], - ), - ); - } -} diff --git a/mvc/lib/src/widgets/todo_item.dart b/mvc/lib/src/widgets/todo_item.dart deleted file mode 100644 index e44b8e1c..00000000 --- a/mvc/lib/src/widgets/todo_item.dart +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class TodoItem extends StatelessWidget { - final DismissDirectionCallback onDismissed; - final GestureTapCallback onTap; - final ValueChanged onCheckboxChanged; - final Map todo; - - TodoItem({ - @required this.onDismissed, - @required this.onTap, - @required this.onCheckboxChanged, - @required this.todo, - }); - - @override - Widget build(BuildContext context) { - return Dismissible( - key: ArchSampleKeys.todoItem(todo['id']), - onDismissed: onDismissed, - child: ListTile( - onTap: onTap, - leading: Checkbox( - key: ArchSampleKeys.todoItemCheckbox(todo['id']), - value: todo['complete'], - onChanged: onCheckboxChanged, - ), - title: Text( - todo['task'], - key: ArchSampleKeys.todoItemTask(todo['id']), - style: Theme.of(context).textTheme.title, - ), - subtitle: Text( - todo['note'], - key: ArchSampleKeys.todoItemNote(todo['id']), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, - ), - ), - ); - } -} diff --git a/mvc/lib/src/widgets/todo_list.dart b/mvc/lib/src/widgets/todo_list.dart deleted file mode 100644 index 77afa557..00000000 --- a/mvc/lib/src/widgets/todo_list.dart +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:mvc/src/screens/detail_screen.dart'; -import 'package:mvc/src/widgets/todo_item.dart'; - -import 'package:mvc/src/Controller.dart'; - -class TodoList extends StatelessWidget { - TodoList({Key key}) : super(key: key); - - static final _con = Con.con; - - @override - Widget build(BuildContext context) { - return Container( - child: Con.isLoading ? _buildLoading : _buildList(), - ); - } - - Center get _buildLoading { - return Center( - child: CircularProgressIndicator( - key: ArchSampleKeys.todosLoading, - ), - ); - } - - ListView _buildList() { - final todos = Con.filteredTodos; - return ListView.builder( - key: ArchSampleKeys.todoList, - itemCount: todos.length, - itemBuilder: (BuildContext context, int index) { - final Map todo = todos.elementAt(index).cast(); - return TodoItem( - todo: todo, - onDismissed: (direction) { - _removeTodo(context, todo); - }, - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) { - return DetailScreen( - todoId: todo['id'], - ); - }, - ), - ).then((todo) { - if (todo is Map && todo.isNotEmpty) { - _showUndoSnackbar(context, todo); - } - }); - }, - onCheckboxChanged: (complete) { - _con.checked(todo); - }, - ); - }, - ); - } - - void _removeTodo(BuildContext context, Map todo) { - _con.remove(todo); - _showUndoSnackbar(context, todo); - } - - void _showUndoSnackbar(BuildContext context, Map todo) { - Scaffold.of(context).showSnackBar( - SnackBar( - key: ArchSampleKeys.snackbar, - duration: Duration(seconds: 2), - content: Text( - ArchSampleLocalizations.of(context).todoDeleted(todo['task']), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - action: SnackBarAction( - key: ArchSampleKeys.snackbarAction(todo['id']), - label: ArchSampleLocalizations.of(context).undo, - onPressed: () { - _con.undo(todo); - }, - ), - ), - ); - } -} diff --git a/mvc/pubspec.yaml b/mvc/pubspec.yaml deleted file mode 100644 index f1ca5380..00000000 --- a/mvc/pubspec.yaml +++ /dev/null @@ -1,80 +0,0 @@ -name: mvc -description: A new Flutter project. - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 - -environment: - sdk: ">=2.1.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - scoped_model_sample: - path: ../scoped_model - todos_app_core: - path: ../todos_app_core - todos_repository_local_storage: - path: ../todos_repository_local_storage - mvc_pattern: - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_driver: - sdk: flutter - test: - mockito: - integration_tests: - path: ../integration_tests - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/mvc/test/todo_list_model_test.dart b/mvc/test/todo_list_model_test.dart deleted file mode 100644 index 560c0326..00000000 --- a/mvc/test/todo_list_model_test.dart +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter_test/flutter_test.dart'; -import 'package:mvc/src/models.dart'; -import 'package:mvc/src/todo_list_model.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -void main() { - group('TodoListModel', () { - test('should check if there are completed todos', () async { - final model = TodoListModel( - repo: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); - await model.loadTodos(); - - expect(model.todos.any((it) => it.complete), true); - }); - - test('should calculate the number of active todos', () async { - final model = TodoListModel( - repo: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); - await model.loadTodos(); - - expect(model.todos.where((it) => !it.complete).toList().length, 2); - }); - - test('should calculate the number of completed todos', () async { - final model = TodoListModel( - repo: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); - await model.loadTodos(); - - expect(model.todos.where((it) => it.complete).toList().length, 1); - }); - - test('should return all todos if the VisibilityFilter is all', () async { - final todos = [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]; - final model = TodoListModel( - repo: MockRepository(todos), activeFilter: VisibilityFilter.all); - await model.loadTodos(); - - expect(model.filteredTodos, todos); - }); - - test('should return active todos if the VisibilityFilter is active', - () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final model = TodoListModel( - repo: MockRepository(todos), - activeFilter: VisibilityFilter.active, - ); - await model.loadTodos(); - - expect(model.filteredTodos, [ - todo1, - todo2, - ]); - }); - - test('should return completed todos if the VisibilityFilter is completed', - () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final model = TodoListModel( - repo: MockRepository(todos), - activeFilter: VisibilityFilter.completed, - ); - await model.loadTodos(); - - expect(model.filteredTodos, [todo3]); - }); - - test('should clear the completed todos', () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final model = TodoListModel( - repo: MockRepository(todos), - ); - await model.loadTodos(); - - model.clearCompleted(); - - expect(model.todos, [ - todo1, - todo2, - ]); - }); - - test('toggle all as complete or incomplete', () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final model = TodoListModel( - repo: MockRepository(todos), - ); - await model.loadTodos(); - - // Toggle all complete - model.toggleAll(); - expect(model.todos.every((t) => t.complete), isTrue); - - // Toggle all incomplete - model.toggleAll(); - expect(model.todos.every((t) => !t.complete), isTrue); - }); - }); -} - -class MockRepository extends TodosRepository { - List entities; - - MockRepository(List todos) - : entities = todos.map((it) => it.toEntity()).toList(); - - @override - Future> loadTodos() { - return Future.value(entities); - } - - @override - Future saveTodos(List todos) { - return Future.sync(() => entities = todos); - } -} diff --git a/mvc/test_driver/todo_app.dart b/mvc/test_driver/todo_app.dart deleted file mode 100644 index f7db8943..00000000 --- a/mvc/test_driver/todo_app.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// This line imports the extension -import 'package:flutter_driver/driver_extension.dart'; -import 'package:mvc/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/mvc/test_driver/todo_app_test.dart b/mvc/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/mvc/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/mvi_base/analysis_options.yaml b/mvi_base/analysis_options.yaml index 97d4b470..f798e77a 100644 --- a/mvi_base/analysis_options.yaml +++ b/mvi_base/analysis_options.yaml @@ -1,14 +1,32 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + analyzer: -# exclude: -# - path/to/excluded/files/** - -# Lint rules and documentation, see http://dart-lang.github.io/linter/lints -linter: - rules: - - cancel_subscriptions - - hash_and_equals - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - test_types_in_equals - - unrelated_type_equality_checks - - valid_regexps + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +# linter: +# rules: +# - camel_case_types + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/mvi_base/lib/mvi_base.dart b/mvi_base/lib/mvi_base.dart index cf8b548d..78b47d53 100644 --- a/mvi_base/lib/mvi_base.dart +++ b/mvi_base/lib/mvi_base.dart @@ -1,13 +1,7 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library blocs; - export 'src/models/models.dart'; export 'src/mvi_core.dart'; export 'src/mvi_stats.dart'; export 'src/mvi_todo.dart'; export 'src/mvi_todos_list.dart'; -export 'src/todos_interactor.dart'; +export 'src/todo_list_interactor.dart'; export 'src/user_interactor.dart'; diff --git a/mvi_base/lib/src/models/models.dart b/mvi_base/lib/src/models/models.dart index f2ba373e..1a60eaa3 100644 --- a/mvi_base/lib/src/models/models.dart +++ b/mvi_base/lib/src/models/models.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - export 'package:mvi_base/src/models/todo.dart'; export 'package:mvi_base/src/models/user.dart'; export 'package:mvi_base/src/models/visibility_filter.dart'; diff --git a/mvi_base/lib/src/models/todo.dart b/mvi_base/lib/src/models/todo.dart index 8864dbfc..ccbe5a6e 100644 --- a/mvi_base/lib/src/models/todo.dart +++ b/mvi_base/lib/src/models/todo.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:meta/meta.dart'; import 'package:mvi_base/src/uuid.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -13,11 +9,10 @@ class Todo { final String note; final String task; - Todo(this.task, {this.complete = false, String note = '', String id}) - : this.note = note ?? '', - this.id = id ?? Uuid().generateV4(); + Todo(this.task, {this.complete = false, this.note = '', String? id}) + : id = id ?? Uuid().generateV4(); - Todo copyWith({bool complete, String id, String note, String task}) { + Todo copyWith({bool? complete, String? id, String? note, String? task}) { return Todo( task ?? this.task, complete: complete ?? this.complete, @@ -52,9 +47,9 @@ class Todo { static Todo fromEntity(TodoEntity entity) { return Todo( entity.task, - complete: entity.complete ?? false, + complete: entity.complete, note: entity.note, - id: entity.id ?? Uuid().generateV4(), + id: entity.id, ); } } diff --git a/mvi_base/lib/src/models/user.dart b/mvi_base/lib/src/models/user.dart index a1fa7b22..97190a6c 100644 --- a/mvi_base/lib/src/models/user.dart +++ b/mvi_base/lib/src/models/user.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:meta/meta.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -9,11 +5,13 @@ import 'package:todos_repository_core/todos_repository_core.dart'; class User { final String displayName; - User(this.displayName); + User({required this.displayName}); - UserEntity toEntity() => UserEntity(displayName: displayName); + UserEntity toEntity() => + UserEntity(displayName: displayName, id: '', photoUrl: ''); - static User fromEntity(UserEntity entity) => User(entity.displayName); + static User fromEntity(UserEntity entity) => + User(displayName: entity.displayName); @override String toString() { diff --git a/mvi_base/lib/src/models/visibility_filter.dart b/mvi_base/lib/src/models/visibility_filter.dart index 11f11982..a47beca1 100644 --- a/mvi_base/lib/src/models/visibility_filter.dart +++ b/mvi_base/lib/src/models/visibility_filter.dart @@ -1,5 +1 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - enum VisibilityFilter { all, active, completed } diff --git a/mvi_base/lib/src/mvi_core.dart b/mvi_base/lib/src/mvi_core.dart index 15234356..f0f62e55 100644 --- a/mvi_base/lib/src/mvi_core.dart +++ b/mvi_base/lib/src/mvi_core.dart @@ -1,14 +1,10 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:meta/meta.dart'; import 'package:rxdart/rxdart.dart'; abstract class MviDisposable { - Future tearDown(); + Future tearDown(); } // A class that should contain a number of broadcast StreamControllers. These @@ -25,10 +21,8 @@ class MviPresenter extends Stream final BehaviorSubject _subject; final List> subscriptions = []; - MviPresenter({ - @required Stream stream, - ViewModel initialModel, - }) : _subject = _createSubject(stream, initialModel); + MviPresenter({required Stream stream, ViewModel? initialModel}) + : _subject = _createSubject(stream, initialModel); // Get the current state. Useful for initial renders or re-renders when we // have already fetched the data @@ -36,28 +30,29 @@ class MviPresenter extends Stream void setUp() {} + @override @mustCallSuper - Future tearDown() => Future.wait( - [_subject.close()]..addAll(subscriptions.map((s) => s.cancel()))); + Future tearDown() => + Future.wait([_subject.close(), ...subscriptions.map((s) => s.cancel())]); - static _createSubject( + static BehaviorSubject _createSubject( Stream model, - ViewState initialState, + ViewState? initialState, ) { - StreamSubscription subscription; - BehaviorSubject _subject; + late StreamSubscription subscription; + late BehaviorSubject subject; + void onListen() { subscription = model.listen( - _subject.add, - onError: _subject.addError, - onDone: _subject.close, + subject.add, + onError: subject.addError, + onDone: subject.close, ); } - ; void onCancel() => subscription.cancel(); - _subject = initialState == null + subject = initialState == null ? BehaviorSubject( onListen: onListen, onCancel: onCancel, @@ -69,20 +64,21 @@ class MviPresenter extends Stream onCancel: onCancel, ); - return _subject; + return subject; } @override StreamSubscription listen( - void Function(ViewModel event) onData, { - Function onError, - void Function() onDone, - bool cancelOnError, - }) => - _subject.stream.listen( - onData, - onError: onError, - onDone: onDone, - cancelOnError: cancelOnError, - ); + void Function(ViewModel event)? onData, { + Function? onError, + void Function()? onDone, + bool? cancelOnError, + }) { + return _subject.stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } } diff --git a/mvi_base/lib/src/mvi_stats.dart b/mvi_base/lib/src/mvi_stats.dart index 39de8ee7..d3c8d643 100644 --- a/mvi_base/lib/src/mvi_stats.dart +++ b/mvi_base/lib/src/mvi_stats.dart @@ -1,20 +1,17 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:mvi_base/mvi_base.dart'; -import 'package:mvi_base/src/mvi_core.dart'; import 'package:rxdart/rxdart.dart'; class StatsPresenter extends MviPresenter { - StatsPresenter(TodosInteractor interactor) - : super( - stream: Rx.combineLatest2( - interactor.todos.map(_numActive), - interactor.todos.map(_numComplete), - (numActive, numComplete) => StatsModel(numActive, numComplete), - ), - ); + StatsPresenter(TodoListInteractor interactor) + : super( + initialModel: StatsModelLoading(), + stream: Rx.combineLatest2( + interactor.todos.map(_numActive), + interactor.todos.map(_numComplete), + (numActive, numComplete) => + StatsModelLoaded(numActive: numActive, numComplete: numComplete), + ), + ); static int _numActive(List todos) { return todos.fold(0, (sum, todo) => !todo.complete ? ++sum : sum); @@ -25,16 +22,20 @@ class StatsPresenter extends MviPresenter { } } -class StatsModel { +sealed class StatsModel {} + +class StatsModelLoading implements StatsModel {} + +class StatsModelLoaded implements StatsModel { final int numActive; final int numComplete; - StatsModel(this.numActive, this.numComplete); + StatsModelLoaded({required this.numActive, required this.numComplete}); @override bool operator ==(Object other) => identical(this, other) || - other is StatsModel && + other is StatsModelLoaded && runtimeType == other.runtimeType && numActive == other.numActive && numComplete == other.numComplete; @@ -44,6 +45,6 @@ class StatsModel { @override String toString() { - return 'StatsModel{numActive: $numActive, numComplete: $numComplete}'; + return 'StatsModelLoaded{numActive: $numActive, numComplete: $numComplete}'; } } diff --git a/mvi_base/lib/src/mvi_todo.dart b/mvi_base/lib/src/mvi_todo.dart index 83544c2c..af7ef2e0 100644 --- a/mvi_base/lib/src/mvi_todo.dart +++ b/mvi_base/lib/src/mvi_todo.dart @@ -1,13 +1,8 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; -import 'package:meta/meta.dart'; import 'package:mvi_base/src/models/models.dart'; import 'package:mvi_base/src/mvi_core.dart'; -import 'package:mvi_base/src/todos_interactor.dart'; +import 'package:mvi_base/src/todo_list_interactor.dart'; mixin DetailView implements MviView { final deleteTodo = StreamController.broadcast(sync: true); @@ -15,25 +10,22 @@ mixin DetailView implements MviView { final updateTodo = StreamController.broadcast(sync: true); @override - Future tearDown() { - return Future.wait([ - deleteTodo.close(), - updateTodo.close(), - ]); + Future tearDown() { + return Future.wait([deleteTodo.close(), updateTodo.close()]); } } class DetailPresenter extends MviPresenter { final DetailView _view; - final TodosInteractor _interactor; + final TodoListInteractor _interactor; DetailPresenter({ - @required String id, - @required DetailView view, - @required TodosInteractor interactor, - }) : _view = view, - _interactor = interactor, - super(stream: interactor.todo(id)); + required String id, + required DetailView view, + required TodoListInteractor interactor, + }) : _view = view, + _interactor = interactor, + super(stream: interactor.todo(id)); @override void setUp() { diff --git a/mvi_base/lib/src/mvi_todos_list.dart b/mvi_base/lib/src/mvi_todos_list.dart index c4fc2179..b2b2ba60 100644 --- a/mvi_base/lib/src/mvi_todos_list.dart +++ b/mvi_base/lib/src/mvi_todos_list.dart @@ -1,18 +1,13 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; -import 'package:meta/meta.dart'; +import 'package:collection/collection.dart'; import 'package:mvi_base/src/models/models.dart'; -import 'package:mvi_base/src/models/user.dart'; import 'package:mvi_base/src/mvi_core.dart'; -import 'package:mvi_base/src/todos_interactor.dart'; +import 'package:mvi_base/src/todo_list_interactor.dart'; import 'package:mvi_base/src/user_interactor.dart'; import 'package:rxdart/rxdart.dart'; -class TodosListModel { +class TodoListModel { final VisibilityFilter activeFilter; final bool allComplete; final bool hasCompletedTodos; @@ -20,16 +15,23 @@ class TodosListModel { final bool loading; final User user; - TodosListModel({ - this.activeFilter, - this.allComplete, - this.hasCompletedTodos, - this.visibleTodos, - this.loading, - this.user, + TodoListModel({ + required this.activeFilter, + required this.allComplete, + required this.hasCompletedTodos, + required this.visibleTodos, + required this.loading, + required this.user, }); - factory TodosListModel.initial() => TodosListModel(loading: true); + factory TodoListModel.initial() => TodoListModel( + loading: true, + activeFilter: VisibilityFilter.all, + allComplete: false, + hasCompletedTodos: false, + visibleTodos: [], + user: User(displayName: ''), + ); @override String toString() { @@ -39,12 +41,12 @@ class TodosListModel { @override bool operator ==(Object other) => identical(this, other) || - other is TodosListModel && + other is TodoListModel && runtimeType == other.runtimeType && activeFilter == other.activeFilter && allComplete == other.allComplete && hasCompletedTodos == other.hasCompletedTodos && - visibleTodos == other.visibleTodos && + const ListEquality().equals(visibleTodos, other.visibleTodos) && loading == other.loading && user == other.user; @@ -58,7 +60,7 @@ class TodosListModel { user.hashCode; } -class TodosListView implements MviView { +mixin class TodoListView implements MviView { final addTodo = StreamController.broadcast(sync: true); final deleteTodo = StreamController.broadcast(sync: true); @@ -73,7 +75,8 @@ class TodosListView implements MviView { VisibilityFilter.all, ); - Future> tearDown() { + @override + Future tearDown() { return Future.wait([ addTodo.close(), deleteTodo.close(), @@ -85,20 +88,20 @@ class TodosListView implements MviView { } } -class TodosListPresenter extends MviPresenter { - final TodosListView _view; - final TodosInteractor _interactor; - - TodosListPresenter({ - @required TodosListView view, - @required TodosInteractor todosInteractor, - @required UserInteractor userInteractor, - }) : _view = view, - _interactor = todosInteractor, - super( - initialModel: TodosListModel.initial(), - stream: _buildStream(view, todosInteractor, userInteractor), - ); +class TodoListPresenter extends MviPresenter { + final TodoListView _view; + final TodoListInteractor _interactor; + + TodoListPresenter({ + required TodoListView view, + required TodoListInteractor todosInteractor, + required UserInteractor userInteractor, + }) : _view = view, + _interactor = todosInteractor, + super( + initialModel: TodoListModel.initial(), + stream: _buildStream(view, todosInteractor, userInteractor), + ); @override void setUp() { @@ -111,9 +114,9 @@ class TodosListPresenter extends MviPresenter { ]); } - static Stream _buildStream( - TodosListView view, - TodosInteractor interactor, + static Stream _buildStream( + TodoListView view, + TodoListInteractor interactor, UserInteractor repository, ) { return Rx.defer(() async* { @@ -129,7 +132,7 @@ class TodosListPresenter extends MviPresenter { _filterTodos, ), (activeFilter, allComplete, hasCompletedTodos, visibleTodos) { - return TodosListModel( + return TodoListModel( user: user, activeFilter: activeFilter, allComplete: allComplete, @@ -149,7 +152,6 @@ class TodosListPresenter extends MviPresenter { case VisibilityFilter.completed: return todos.where((todo) => todo.complete).toList(); case VisibilityFilter.all: - default: return todos; } } diff --git a/mvi_base/lib/src/todo_list_interactor.dart b/mvi_base/lib/src/todo_list_interactor.dart new file mode 100644 index 00000000..9e3f63a7 --- /dev/null +++ b/mvi_base/lib/src/todo_list_interactor.dart @@ -0,0 +1,76 @@ +import 'dart:async'; + +import 'package:collection/collection.dart'; +import 'package:mvi_base/mvi_base.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:todos_repository_core/todos_repository_core.dart'; + +class TodoListInteractor { + final ReactiveTodosRepository repository; + + TodoListInteractor(this.repository); + + Stream> get todos { + return repository.todos().map( + (entities) => entities.map(Todo.fromEntity).toList(), + ); + } + + Stream todo(String id) { + return todos + .map((todos) => todos.firstWhereOrNull((todo) => todo.id == id)) + .whereNotNull(); + } + + Stream get allComplete => todos.map(_allComplete); + + Stream get hasCompletedTodos => todos.map(_hasCompletedTodos); + + Future updateTodo(Todo todo) => repository.updateTodo(todo.toEntity()); + + Future addNewTodo(Todo todo) => repository.addNewTodo(todo.toEntity()); + + Future deleteTodo(String id) => repository.deleteTodo([id]); + + Future clearCompleted([_]) async => + repository.deleteTodo(await todos.map(_completedTodoIds).first); + + Future> toggleAll([_]) async { + final updates = await todos.map(_todosToUpdate).first; + + return Future.wait( + updates.map((update) => repository.updateTodo(update.toEntity())), + ); + } + + static bool _hasCompletedTodos(List todos) { + return todos.any((todo) => todo.complete); + } + + static List _completedTodoIds(List todos) { + return todos.fold>([], (prev, todo) { + if (todo.complete) { + return prev..add(todo.id); + } else { + return prev; + } + }); + } + + static List _todosToUpdate(List todos) { + final allComplete = _allComplete(todos); + + return todos.fold>([], (prev, todo) { + if (allComplete) { + return prev..add(todo.copyWith(complete: false)); + } else if (!allComplete && !todo.complete) { + return prev..add(todo.copyWith(complete: true)); + } else { + return prev; + } + }); + } + + static bool _allComplete(List todos) => + todos.every((todo) => todo.complete); +} diff --git a/mvi_base/lib/src/todos_interactor.dart b/mvi_base/lib/src/todos_interactor.dart deleted file mode 100644 index 9abcb080..00000000 --- a/mvi_base/lib/src/todos_interactor.dart +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:mvi_base/mvi_base.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -class TodosInteractor { - final ReactiveTodosRepository repository; - - TodosInteractor(this.repository); - - Stream> get todos { - return repository - .todos() - .map((entities) => entities.map(Todo.fromEntity).toList()); - } - - Stream todo(String id) { - return todos.map((todos) { - return todos.firstWhere( - (todo) => todo.id == id, - orElse: () => null, - ); - }).where((todo) => todo != null); - } - - Stream get allComplete => todos.map(_allComplete); - - Stream get hasCompletedTodos => todos.map(_hasCompletedTodos); - - Future updateTodo(Todo todo) => repository.updateTodo(todo.toEntity()); - - Future addNewTodo(Todo todo) => repository.addNewTodo(todo.toEntity()); - - Future deleteTodo(String id) => repository.deleteTodo([id]); - - Future clearCompleted([_]) async => - repository.deleteTodo(await todos.map(_completedTodoIds).first); - - Future> toggleAll([_]) async { - final updates = await todos.map(_todosToUpdate).first; - - return Future.wait( - updates.map((update) => repository.updateTodo(update.toEntity()))); - } - - static bool _hasCompletedTodos(List todos) { - return todos.any((todo) => todo.complete); - } - - static List _completedTodoIds(List todos) { - return todos.fold>([], (prev, todo) { - if (todo.complete) { - return prev..add(todo.id); - } else { - return prev; - } - }); - } - - static List _todosToUpdate(List todos) { - final allComplete = _allComplete(todos); - - return todos.fold>([], (prev, todo) { - if (allComplete) { - return prev..add(todo.copyWith(complete: false)); - } else if (!allComplete && !todo.complete) { - return prev..add(todo.copyWith(complete: true)); - } else { - return prev; - } - }); - } - - static bool _allComplete(List todos) => - todos.every((todo) => todo.complete); -} diff --git a/mvi_base/lib/src/user_interactor.dart b/mvi_base/lib/src/user_interactor.dart index 7dbef8e2..257207e4 100644 --- a/mvi_base/lib/src/user_interactor.dart +++ b/mvi_base/lib/src/user_interactor.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:mvi_base/src/models/user.dart'; @@ -12,5 +8,6 @@ class UserInteractor { UserInteractor(UserRepository repository) : _repository = repository; - Future login() async => User((await _repository.login()).displayName); + Future login() async => + User(displayName: (await _repository.login()).displayName); } diff --git a/mvi_base/lib/src/uuid.dart b/mvi_base/lib/src/uuid.dart index 1b6b26da..73d193cb 100644 --- a/mvi_base/lib/src/uuid.dart +++ b/mvi_base/lib/src/uuid.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:math'; /// A UUID generator, useful for generating unique IDs for your Todos. diff --git a/mvi_base/pubspec.yaml b/mvi_base/pubspec.yaml index 6097d278..47553ece 100644 --- a/mvi_base/pubspec.yaml +++ b/mvi_base/pubspec.yaml @@ -2,13 +2,17 @@ name: mvi_base description: The MI parts of an MVI app. environment: - sdk: '>=2.0.0-dev.28.0 <3.0.0' + sdk: ^3.9.0 dependencies: + collection: + meta: + rxdart: todos_repository_core: path: ../todos_repository_core - rxdart: ^0.23.1 dev_dependencies: + lints: test: mockito: + build_runner: diff --git a/mvi_base/test/all_tests.dart b/mvi_base/test/all_tests.dart deleted file mode 100644 index 04018209..00000000 --- a/mvi_base/test/all_tests.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'mvi_stats_test.dart' as mviStats; -import 'mvi_todo_test.dart' as mviTodo; -import 'mvi_todos_list_test.dart' as mviTodosList; -import 'todos_interactor_test.dart' as todosInteractor; -import 'user_interactor_test.dart' as userInteractor; - -void main() { - mviStats.main(); - mviTodo.main(); - mviTodosList.main(); - todosInteractor.main(); - userInteractor.main(); -} diff --git a/mvi_base/test/mvi_stats_test.dart b/mvi_base/test/mvi_stats_test.dart index a030e8b1..b76eef0f 100644 --- a/mvi_base/test/mvi_stats_test.dart +++ b/mvi_base/test/mvi_stats_test.dart @@ -1,19 +1,17 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:mvi_base/mvi_base.dart'; import 'package:test/test.dart'; -class MockTodosInteractor extends Mock implements TodosInteractor {} +import 'mvi_stats_test.mocks.dart'; +@GenerateNiceMocks([MockSpec()]) void main() { group('MviStats', () { test('should stream the number of active and completed todos', () { - final interactor = MockTodosInteractor(); + final interactor = MockTodoListInteractor(); final todos = [ Todo('Hi', complete: true), Todo('There', complete: true), @@ -26,7 +24,7 @@ void main() { expect( presenter, - emitsThrough(StatsModel(1, 2)), + emitsThrough(StatsModelLoaded(numActive: 1, numComplete: 2)), ); }); }); diff --git a/mvi_base/test/mvi_stats_test.mocks.dart b/mvi_base/test/mvi_stats_test.mocks.dart new file mode 100644 index 00000000..86c07709 --- /dev/null +++ b/mvi_base/test/mvi_stats_test.mocks.dart @@ -0,0 +1,135 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in mvi_base/test/mvi_stats_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:mvi_base/mvi_base.dart' as _i3; +import 'package:todos_repository_core/todos_repository_core.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member + +class _FakeReactiveTodosRepository_0 extends _i1.SmartFake + implements _i2.ReactiveTodosRepository { + _FakeReactiveTodosRepository_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [TodoListInteractor]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodoListInteractor extends _i1.Mock + implements _i3.TodoListInteractor { + @override + _i2.ReactiveTodosRepository get repository => + (super.noSuchMethod( + Invocation.getter(#repository), + returnValue: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + returnValueForMissingStub: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + ) + as _i2.ReactiveTodosRepository); + + @override + _i4.Stream> get todos => + (super.noSuchMethod( + Invocation.getter(#todos), + returnValue: _i4.Stream>.empty(), + returnValueForMissingStub: _i4.Stream>.empty(), + ) + as _i4.Stream>); + + @override + _i4.Stream get allComplete => + (super.noSuchMethod( + Invocation.getter(#allComplete), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream get hasCompletedTodos => + (super.noSuchMethod( + Invocation.getter(#hasCompletedTodos), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream<_i3.Todo> todo(String? id) => + (super.noSuchMethod( + Invocation.method(#todo, [id]), + returnValue: _i4.Stream<_i3.Todo>.empty(), + returnValueForMissingStub: _i4.Stream<_i3.Todo>.empty(), + ) + as _i4.Stream<_i3.Todo>); + + @override + _i4.Future updateTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future addNewTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future deleteTodo(String? id) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [id]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future clearCompleted([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#clearCompleted, [_0]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future> toggleAll([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#toggleAll, [_0]), + returnValue: _i4.Future>.value([]), + returnValueForMissingStub: _i4.Future>.value( + [], + ), + ) + as _i4.Future>); +} diff --git a/mvi_base/test/mvi_todo_test.dart b/mvi_base/test/mvi_todo_test.dart index d4a158c0..a61a2739 100644 --- a/mvi_base/test/mvi_todo_test.dart +++ b/mvi_base/test/mvi_todo_test.dart @@ -1,31 +1,29 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:mvi_base/mvi_base.dart'; -import 'package:mvi_base/src/models/models.dart'; import 'package:test/test.dart'; -class MockTodosInteractor extends Mock implements TodosInteractor {} +import 'mvi_todo_test.mocks.dart'; -class MockView extends Object with DetailView {} +class MockDetailView extends Mock with DetailView {} +@GenerateNiceMocks([MockSpec()]) void main() { group('MviTodo', () { group('Presenter', () { test('should load a todo', () { - final interactor = MockTodosInteractor(); + final interactor = MockTodoListInteractor(); final todo = Todo('Hallo'); - when(interactor.todo(todo.id)) - .thenAnswer((_) => Stream.fromIterable([todo])); + when( + interactor.todo(todo.id), + ).thenAnswer((_) => Stream.fromIterable([todo])); final presenter = DetailPresenter( id: todo.id, - view: MockView(), + view: MockDetailView(), interactor: interactor, ); @@ -33,12 +31,15 @@ void main() { }); test('should send deletions to the interactor', () async { - final interactor = MockTodosInteractor(); + final interactor = MockTodoListInteractor(); final todo = Todo('Hallo'); - final view = MockView(); + final view = MockDetailView(); + + when( + interactor.todo(todo.id), + ).thenAnswer((_) => Stream.fromIterable([todo])); - when(interactor.todo(todo.id)) - .thenAnswer((_) => Stream.fromIterable([todo])); + when(interactor.deleteTodo(todo.id)).thenAnswer((_) => Future.value()); final presenter = DetailPresenter( id: todo.id, @@ -52,12 +53,13 @@ void main() { }); test('should send updates to the interactor', () async { - final interactor = MockTodosInteractor(); + final interactor = MockTodoListInteractor(); final todo = Todo('Hallo'); - final view = MockView(); + final view = MockDetailView(); - when(interactor.todo(todo.id)) - .thenAnswer((_) => Stream.fromIterable([todo])); + when( + interactor.todo(todo.id), + ).thenAnswer((_) => Stream.fromIterable([todo])); final presenter = DetailPresenter( id: todo.id, @@ -73,7 +75,7 @@ void main() { group('View', () { test('should clean up after itself', () async { - final view = MockView(); + final view = MockDetailView(); view.tearDown(); diff --git a/mvi_base/test/mvi_todo_test.mocks.dart b/mvi_base/test/mvi_todo_test.mocks.dart new file mode 100644 index 00000000..7bfca2bf --- /dev/null +++ b/mvi_base/test/mvi_todo_test.mocks.dart @@ -0,0 +1,185 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in mvi_base/test/mvi_todo_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:mvi_base/mvi_base.dart' as _i4; +import 'package:todos_repository_core/todos_repository_core.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member + +class _FakeReactiveTodosRepository_0 extends _i1.SmartFake + implements _i2.ReactiveTodosRepository { + _FakeReactiveTodosRepository_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakeStreamController_1 extends _i1.SmartFake + implements _i3.StreamController { + _FakeStreamController_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [TodoListInteractor]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodoListInteractor extends _i1.Mock + implements _i4.TodoListInteractor { + @override + _i2.ReactiveTodosRepository get repository => + (super.noSuchMethod( + Invocation.getter(#repository), + returnValue: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + returnValueForMissingStub: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + ) + as _i2.ReactiveTodosRepository); + + @override + _i3.Stream> get todos => + (super.noSuchMethod( + Invocation.getter(#todos), + returnValue: _i3.Stream>.empty(), + returnValueForMissingStub: _i3.Stream>.empty(), + ) + as _i3.Stream>); + + @override + _i3.Stream get allComplete => + (super.noSuchMethod( + Invocation.getter(#allComplete), + returnValue: _i3.Stream.empty(), + returnValueForMissingStub: _i3.Stream.empty(), + ) + as _i3.Stream); + + @override + _i3.Stream get hasCompletedTodos => + (super.noSuchMethod( + Invocation.getter(#hasCompletedTodos), + returnValue: _i3.Stream.empty(), + returnValueForMissingStub: _i3.Stream.empty(), + ) + as _i3.Stream); + + @override + _i3.Stream<_i4.Todo> todo(String? id) => + (super.noSuchMethod( + Invocation.method(#todo, [id]), + returnValue: _i3.Stream<_i4.Todo>.empty(), + returnValueForMissingStub: _i3.Stream<_i4.Todo>.empty(), + ) + as _i3.Stream<_i4.Todo>); + + @override + _i3.Future updateTodo(_i4.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future addNewTodo(_i4.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future deleteTodo(String? id) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [id]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future clearCompleted([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#clearCompleted, [_0]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future> toggleAll([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#toggleAll, [_0]), + returnValue: _i3.Future>.value([]), + returnValueForMissingStub: _i3.Future>.value( + [], + ), + ) + as _i3.Future>); +} + +/// A class which mocks [DetailView]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockDetailView extends _i1.Mock implements _i4.DetailView { + @override + _i3.StreamController get deleteTodo => + (super.noSuchMethod( + Invocation.getter(#deleteTodo), + returnValue: _FakeStreamController_1( + this, + Invocation.getter(#deleteTodo), + ), + returnValueForMissingStub: _FakeStreamController_1( + this, + Invocation.getter(#deleteTodo), + ), + ) + as _i3.StreamController); + + @override + _i3.StreamController<_i4.Todo> get updateTodo => + (super.noSuchMethod( + Invocation.getter(#updateTodo), + returnValue: _FakeStreamController_1<_i4.Todo>( + this, + Invocation.getter(#updateTodo), + ), + returnValueForMissingStub: _FakeStreamController_1<_i4.Todo>( + this, + Invocation.getter(#updateTodo), + ), + ) + as _i3.StreamController<_i4.Todo>); + + @override + _i3.Future tearDown() => + (super.noSuchMethod( + Invocation.method(#tearDown, []), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); +} diff --git a/mvi_base/test/mvi_todos_list_test.dart b/mvi_base/test/mvi_todos_list_test.dart index 2d983858..01bc34ec 100644 --- a/mvi_base/test/mvi_todos_list_test.dart +++ b/mvi_base/test/mvi_todos_list_test.dart @@ -1,26 +1,18 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:mvi_base/mvi_base.dart'; -import 'package:mvi_base/src/models/models.dart'; import 'package:test/test.dart'; -class MockTodosListInteractor extends Mock implements TodosInteractor {} - -class MockUserInteractor implements UserInteractor { - @override - Future login() => Future.sync(() => User('Erica')); -} +import 'mvi_todos_list_test.mocks.dart'; +@GenerateNiceMocks([MockSpec(), MockSpec()]) void main() { group('MviTodosList', () { group('View', () { test('should clean up after itself', () { - final view = TodosListView(); + final view = TodoListView(); view.tearDown(); @@ -35,30 +27,32 @@ void main() { group('Presenter', () { test('should have an initial state', () { - final interactor = MockTodosListInteractor(); - final view = TodosListView(); + final interactor = MockTodoListInteractor(); + final view = TodoListView(); - final presenter = TodosListPresenter( + final presenter = TodoListPresenter( view: view, todosInteractor: interactor, userInteractor: MockUserInteractor(), ); - expect(presenter.latest, TodosListModel.initial()); + expect(presenter.latest, TodoListModel.initial()); }); test('should show all todos by default', () { - final interactor = MockTodosListInteractor(); - final view = TodosListView(); + final interactor = MockTodoListInteractor(); + final view = TodoListView(); final todos = [Todo('Hi')]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); - when(interactor.allComplete) - .thenAnswer((_) => Stream.fromIterable([false])); - when(interactor.hasCompletedTodos) - .thenAnswer((_) => Stream.fromIterable([false])); - - final presenter = TodosListPresenter( + when( + interactor.allComplete, + ).thenAnswer((_) => Stream.fromIterable([false])); + when( + interactor.hasCompletedTodos, + ).thenAnswer((_) => Stream.fromIterable([false])); + + final presenter = TodoListPresenter( view: view, todosInteractor: interactor, userInteractor: MockUserInteractor(), @@ -66,134 +60,131 @@ void main() { expect( presenter, - emitsThrough(ModelWith( - activeFilter: VisibilityFilter.all, - visibleTodos: todos, - )), + emitsThrough( + ModelWith(activeFilter: VisibilityFilter.all, visibleTodos: todos), + ), ); }); test('should display completed todos', () { - final interactor = MockTodosListInteractor(); - final view = TodosListView(); + final interactor = MockTodoListInteractor(); + final view = TodoListView(); final todos = [ Todo('Hallo', complete: false), Todo('Friend', complete: true), ]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); - when(interactor.allComplete) - .thenAnswer((_) => Stream.fromIterable([false])); - when(interactor.hasCompletedTodos) - .thenAnswer((_) => Stream.fromIterable([false])); - - final presenter = TodosListPresenter( + when( + interactor.allComplete, + ).thenAnswer((_) => Stream.fromIterable([false])); + when( + interactor.hasCompletedTodos, + ).thenAnswer((_) => Stream.fromIterable([false])); + + final presenter = TodoListPresenter( view: view, todosInteractor: interactor, userInteractor: MockUserInteractor(), ); view.updateFilter.add(VisibilityFilter.completed); - expect( - presenter, - emitsThrough(ModelWith(visibleTodos: [todos.last])), - ); + expect(presenter, emitsThrough(ModelWith(visibleTodos: [todos.last]))); }); test('should display active todos', () { - final interactor = MockTodosListInteractor(); - final view = TodosListView(); + final interactor = MockTodoListInteractor(); + final view = TodoListView(); final todos = [ Todo('Hallo', complete: false), Todo('Friend', complete: true), ]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); - when(interactor.allComplete) - .thenAnswer((_) => Stream.fromIterable([false])); - when(interactor.hasCompletedTodos) - .thenAnswer((_) => Stream.fromIterable([false])); - - final presenter = TodosListPresenter( + when( + interactor.allComplete, + ).thenAnswer((_) => Stream.fromIterable([false])); + when( + interactor.hasCompletedTodos, + ).thenAnswer((_) => Stream.fromIterable([false])); + + final presenter = TodoListPresenter( view: view, todosInteractor: interactor, userInteractor: MockUserInteractor(), ); view.updateFilter.add(VisibilityFilter.active); - expect( - presenter, - emitsThrough(ModelWith(visibleTodos: [todos.first])), - ); + expect(presenter, emitsThrough(ModelWith(visibleTodos: [todos.first]))); }); test('allComplete should stream state of interactor', () { - final interactor = MockTodosListInteractor(); - final view = TodosListView(); + final interactor = MockTodoListInteractor(); + final view = TodoListView(); final todos = [ Todo('Hallo', complete: false), Todo('Friend', complete: true), ]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); - when(interactor.allComplete) - .thenAnswer((_) => Stream.fromIterable([false])); - when(interactor.hasCompletedTodos) - .thenAnswer((_) => Stream.fromIterable([false])); - - final presenter = TodosListPresenter( + when( + interactor.allComplete, + ).thenAnswer((_) => Stream.fromIterable([false])); + when( + interactor.hasCompletedTodos, + ).thenAnswer((_) => Stream.fromIterable([false])); + + final presenter = TodoListPresenter( view: view, todosInteractor: interactor, userInteractor: MockUserInteractor(), ); - expect( - presenter, - emitsThrough(ModelWith(allComplete: false)), - ); + expect(presenter, emitsThrough(ModelWith(allComplete: false))); }); test('hasCompletedTodos should reflect the interactor', () { - final interactor = MockTodosListInteractor(); - final view = TodosListView(); + final interactor = MockTodoListInteractor(); + final view = TodoListView(); final todos = [ Todo('Hallo', complete: false), Todo('Friend', complete: true), ]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); - when(interactor.allComplete) - .thenAnswer((_) => Stream.fromIterable([false])); - when(interactor.hasCompletedTodos) - .thenAnswer((_) => Stream.fromIterable([true])); - - final presenter = TodosListPresenter( + when( + interactor.allComplete, + ).thenAnswer((_) => Stream.fromIterable([false])); + when( + interactor.hasCompletedTodos, + ).thenAnswer((_) => Stream.fromIterable([true])); + + final presenter = TodoListPresenter( view: view, todosInteractor: interactor, userInteractor: MockUserInteractor(), ); - expect( - presenter, - emitsThrough(ModelWith(hasCompletedTodos: true)), - ); + expect(presenter, emitsThrough(ModelWith(hasCompletedTodos: true))); }); test('should add todos to the interactor', () async { - final interactor = MockTodosListInteractor(); - final view = TodosListView(); + final interactor = MockTodoListInteractor(); + final view = TodoListView(); final todos = [ Todo('Hallo', complete: false), Todo('Friend', complete: true), ]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); - when(interactor.allComplete) - .thenAnswer((_) => Stream.fromIterable([false])); - when(interactor.hasCompletedTodos) - .thenAnswer((_) => Stream.fromIterable([true])); - - final presenter = TodosListPresenter( + when( + interactor.allComplete, + ).thenAnswer((_) => Stream.fromIterable([false])); + when( + interactor.hasCompletedTodos, + ).thenAnswer((_) => Stream.fromIterable([true])); + + final presenter = TodoListPresenter( view: view, todosInteractor: interactor, userInteractor: MockUserInteractor(), @@ -205,20 +196,22 @@ void main() { }); test('should send deletions to the interactor', () async { - final interactor = MockTodosListInteractor(); - final view = TodosListView(); + final interactor = MockTodoListInteractor(); + final view = TodoListView(); final todos = [ Todo('Hallo', complete: false), Todo('Friend', complete: true), ]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); - when(interactor.allComplete) - .thenAnswer((_) => Stream.fromIterable([false])); - when(interactor.hasCompletedTodos) - .thenAnswer((_) => Stream.fromIterable([true])); - - final presenter = TodosListPresenter( + when( + interactor.allComplete, + ).thenAnswer((_) => Stream.fromIterable([false])); + when( + interactor.hasCompletedTodos, + ).thenAnswer((_) => Stream.fromIterable([true])); + + final presenter = TodoListPresenter( view: view, todosInteractor: interactor, userInteractor: MockUserInteractor(), @@ -230,20 +223,22 @@ void main() { }); test('should remove completed todos from the interactor', () async { - final interactor = MockTodosListInteractor(); - final view = TodosListView(); + final interactor = MockTodoListInteractor(); + final view = TodoListView(); final todos = [ Todo('Hallo', complete: false), Todo('Friend', complete: true), ]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); - when(interactor.allComplete) - .thenAnswer((_) => Stream.fromIterable([false])); - when(interactor.hasCompletedTodos) - .thenAnswer((_) => Stream.fromIterable([true])); - - final presenter = TodosListPresenter( + when( + interactor.allComplete, + ).thenAnswer((_) => Stream.fromIterable([false])); + when( + interactor.hasCompletedTodos, + ).thenAnswer((_) => Stream.fromIterable([true])); + + final presenter = TodoListPresenter( view: view, todosInteractor: interactor, userInteractor: MockUserInteractor(), @@ -255,20 +250,22 @@ void main() { }); test('should toggle complete', () async { - final interactor = MockTodosListInteractor(); - final view = TodosListView(); + final interactor = MockTodoListInteractor(); + final view = TodoListView(); final todos = [ Todo('Hallo', complete: false), Todo('Friend', complete: true), ]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); - when(interactor.allComplete) - .thenAnswer((_) => Stream.fromIterable([false])); - when(interactor.hasCompletedTodos) - .thenAnswer((_) => Stream.fromIterable([true])); - - final presenter = TodosListPresenter( + when( + interactor.allComplete, + ).thenAnswer((_) => Stream.fromIterable([false])); + when( + interactor.hasCompletedTodos, + ).thenAnswer((_) => Stream.fromIterable([true])); + + final presenter = TodoListPresenter( view: view, todosInteractor: interactor, userInteractor: MockUserInteractor(), @@ -283,11 +280,11 @@ void main() { } class ModelWith extends Matcher { - final VisibilityFilter activeFilter; - final bool allComplete; - final bool hasCompletedTodos; - final List visibleTodos; - final bool loading; + final VisibilityFilter? activeFilter; + final bool? allComplete; + final bool? hasCompletedTodos; + final List? visibleTodos; + final bool? loading; String errors = ''; ModelWith({ @@ -304,11 +301,11 @@ class ModelWith extends Matcher { } @override - bool matches(dynamic item, Map matchState) { - if (item is TodosListModel) { + bool matches(dynamic item, Map matchState) { + if (item is TodoListModel) { bool match = true; if (visibleTodos != null) { - match = _listsEqual(visibleTodos, item.visibleTodos); + match = _listsEqual(visibleTodos!, item.visibleTodos); errors += ' visibleTodos'; } @@ -339,7 +336,7 @@ class ModelWith extends Matcher { } static bool _listsEqual(List first, List second) { - if (first.length != second?.length) return false; + if (first.length != second.length) return false; for (int i = 0; i < first.length; i++) { if (first[i] != second[i]) { diff --git a/mvi_base/test/mvi_todos_list_test.mocks.dart b/mvi_base/test/mvi_todos_list_test.mocks.dart new file mode 100644 index 00000000..30dff54b --- /dev/null +++ b/mvi_base/test/mvi_todos_list_test.mocks.dart @@ -0,0 +1,158 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in mvi_base/test/mvi_todos_list_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:mvi_base/mvi_base.dart' as _i3; +import 'package:todos_repository_core/todos_repository_core.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member + +class _FakeReactiveTodosRepository_0 extends _i1.SmartFake + implements _i2.ReactiveTodosRepository { + _FakeReactiveTodosRepository_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakeUser_1 extends _i1.SmartFake implements _i3.User { + _FakeUser_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [TodoListInteractor]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodoListInteractor extends _i1.Mock + implements _i3.TodoListInteractor { + @override + _i2.ReactiveTodosRepository get repository => + (super.noSuchMethod( + Invocation.getter(#repository), + returnValue: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + returnValueForMissingStub: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + ) + as _i2.ReactiveTodosRepository); + + @override + _i4.Stream> get todos => + (super.noSuchMethod( + Invocation.getter(#todos), + returnValue: _i4.Stream>.empty(), + returnValueForMissingStub: _i4.Stream>.empty(), + ) + as _i4.Stream>); + + @override + _i4.Stream get allComplete => + (super.noSuchMethod( + Invocation.getter(#allComplete), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream get hasCompletedTodos => + (super.noSuchMethod( + Invocation.getter(#hasCompletedTodos), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream<_i3.Todo> todo(String? id) => + (super.noSuchMethod( + Invocation.method(#todo, [id]), + returnValue: _i4.Stream<_i3.Todo>.empty(), + returnValueForMissingStub: _i4.Stream<_i3.Todo>.empty(), + ) + as _i4.Stream<_i3.Todo>); + + @override + _i4.Future updateTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future addNewTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future deleteTodo(String? id) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [id]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future clearCompleted([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#clearCompleted, [_0]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future> toggleAll([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#toggleAll, [_0]), + returnValue: _i4.Future>.value([]), + returnValueForMissingStub: _i4.Future>.value( + [], + ), + ) + as _i4.Future>); +} + +/// A class which mocks [UserInteractor]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockUserInteractor extends _i1.Mock implements _i3.UserInteractor { + @override + _i4.Future<_i3.User> login() => + (super.noSuchMethod( + Invocation.method(#login, []), + returnValue: _i4.Future<_i3.User>.value( + _FakeUser_1(this, Invocation.method(#login, [])), + ), + returnValueForMissingStub: _i4.Future<_i3.User>.value( + _FakeUser_1(this, Invocation.method(#login, [])), + ), + ) + as _i4.Future<_i3.User>); +} diff --git a/mvi_base/test/todos_interactor_test.dart b/mvi_base/test/todos_interactor_test.dart index 51b891c3..9783966d 100644 --- a/mvi_base/test/todos_interactor_test.dart +++ b/mvi_base/test/todos_interactor_test.dart @@ -1,23 +1,20 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:mvi_base/mvi_base.dart'; import 'package:rxdart/rxdart.dart'; import 'package:test/test.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; -class MockReactiveTodosRepository extends Mock - implements ReactiveTodosRepository {} +import 'todos_interactor_test.mocks.dart'; +@GenerateNiceMocks([MockSpec()]) void main() { group('TodosListInteractor', () { test('should convert repo entities into Todos', () { final repository = MockReactiveTodosRepository(); - final interactor = TodosInteractor(repository); + final interactor = TodoListInteractor(repository); final todos = [TodoEntity('Hallo', '1', "Note", false)]; when(repository.todos()).thenAnswer((_) => Stream.fromIterable([todos])); @@ -27,7 +24,7 @@ void main() { test('allComplete should stream false if some todos incomplete', () { final repository = MockReactiveTodosRepository(); - final interactor = TodosInteractor(repository); + final interactor = TodoListInteractor(repository); final todos = [ TodoEntity('Hallo', '1', "Note", false), TodoEntity('Friend', '2', "Note", true), @@ -40,7 +37,7 @@ void main() { test('allComplete should stream true when all todos are complete', () { final repository = MockReactiveTodosRepository(); - final interactor = TodosInteractor(repository); + final interactor = TodoListInteractor(repository); final todos = [ TodoEntity('Hallo', '1', "Note", true), TodoEntity('Friend', '2', "Note", true), @@ -52,7 +49,7 @@ void main() { test('hasCompletedTodos should be true when all todos are complete', () { final repository = MockReactiveTodosRepository(); - final interactor = TodosInteractor(repository); + final interactor = TodoListInteractor(repository); final todos = [ TodoEntity('Hallo', '1', "Note", true), TodoEntity('Friend', '2', "Note", true), @@ -65,7 +62,7 @@ void main() { test('hasCompletedTodos should be true when some todos are complete', () { final repository = MockReactiveTodosRepository(); - final interactor = TodosInteractor(repository); + final interactor = TodoListInteractor(repository); final todos = [ TodoEntity('Hallo', '1', "Note", false), TodoEntity('Friend', '2', "Note", true), @@ -78,7 +75,7 @@ void main() { test('hasCompletedTodos should be false when all todos are incomplete', () { final repository = MockReactiveTodosRepository(); - final interactor = TodosInteractor(repository); + final interactor = TodoListInteractor(repository); final todos = [ TodoEntity('Hallo', '1', "Note", false), TodoEntity('Friend', '2', "Note", false), @@ -91,12 +88,13 @@ void main() { test('should add todos to the repo', () async { final repository = MockReactiveTodosRepository(); - final interactor = TodosInteractor(repository); + final interactor = TodoListInteractor(repository); final todo = Todo("AddMe"); when(repository.todos()).thenAnswer((_) => Stream.empty()); - when(repository.addNewTodo(todo.toEntity())) - .thenAnswer((_) => Future.value()); + when( + repository.addNewTodo(todo.toEntity()), + ).thenAnswer((_) => Future.value()); interactor.addNewTodo(todo); @@ -105,7 +103,7 @@ void main() { test('should send deletions to the repo', () async { final repository = MockReactiveTodosRepository(); - final interactor = TodosInteractor(repository); + final interactor = TodoListInteractor(repository); when(repository.todos()).thenAnswer((_) => Stream.empty()); when(repository.deleteTodo(['1'])).thenAnswer((_) => Future.value()); @@ -117,7 +115,7 @@ void main() { test('should remove completed todos from the repo', () async { final repository = MockReactiveTodosRepository(); - final interactor = TodosInteractor(repository); + final interactor = TodoListInteractor(repository); final todos = [ TodoEntity('Hallo', '1', "Note", false), TodoEntity('Friend', '2', "Note", true), @@ -133,7 +131,7 @@ void main() { test('if some todos incomplete, should toggle todos complete', () async { final repository = MockReactiveTodosRepository(); - final interactor = TodosInteractor(repository); + final interactor = TodoListInteractor(repository); final e1 = TodoEntity('Hallo', '1', "Note", false); final e1Update = TodoEntity('Hallo', '1', "Note", true); final e2 = TodoEntity('Friend', '2', "Note", true); @@ -144,8 +142,9 @@ void main() { ); when(repository.todos()).thenAnswer((_) => source.stream); - when(repository.updateTodo(e1Update)) - .thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e1Update), + ).thenAnswer((_) => Future.sync(() {})); await interactor.toggleAll(null); @@ -154,7 +153,7 @@ void main() { test('if all todos incomplete, should toggle all todos complete', () async { final repository = MockReactiveTodosRepository(); - final interactor = TodosInteractor(repository); + final interactor = TodoListInteractor(repository); final e1 = TodoEntity('Hallo', '1', "Note", false); final e1Update = TodoEntity('Hallo', '1', "Note", true); final e2 = TodoEntity('Friend', '2', "Note", false); @@ -166,10 +165,12 @@ void main() { ); when(repository.todos()).thenAnswer((_) => source.stream); - when(repository.updateTodo(e1Update)) - .thenAnswer((_) => Future.sync(() {})); - when(repository.updateTodo(e2Update)) - .thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e1Update), + ).thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e2Update), + ).thenAnswer((_) => Future.sync(() {})); await interactor.toggleAll(null); @@ -179,7 +180,7 @@ void main() { test('if all todos complete, should toggle todos incomplete', () async { final repository = MockReactiveTodosRepository(); - final interactor = TodosInteractor(repository); + final interactor = TodoListInteractor(repository); final e1 = TodoEntity('Hallo', '1', "Note", true); final e1Update = TodoEntity('Hallo', '1', "Note", false); final e2 = TodoEntity('Friend', '2', "Note", true); @@ -191,10 +192,12 @@ void main() { ); when(repository.todos()).thenAnswer((_) => source.stream); - when(repository.updateTodo(e1Update)) - .thenAnswer((_) => Future.sync(() {})); - when(repository.updateTodo(e2Update)) - .thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e1Update), + ).thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e2Update), + ).thenAnswer((_) => Future.sync(() {})); await interactor.toggleAll(null); diff --git a/mvi_base/test/todos_interactor_test.mocks.dart b/mvi_base/test/todos_interactor_test.mocks.dart new file mode 100644 index 00000000..14b3d153 --- /dev/null +++ b/mvi_base/test/todos_interactor_test.mocks.dart @@ -0,0 +1,67 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in mvi_base/test/todos_interactor_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:todos_repository_core/src/reactive_repository.dart' as _i2; +import 'package:todos_repository_core/src/todo_entity.dart' as _i4; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member + +/// A class which mocks [ReactiveTodosRepository]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockReactiveTodosRepository extends _i1.Mock + implements _i2.ReactiveTodosRepository { + @override + _i3.Future addNewTodo(_i4.TodoEntity? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future deleteTodo(List? idList) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [idList]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Stream> todos() => + (super.noSuchMethod( + Invocation.method(#todos, []), + returnValue: _i3.Stream>.empty(), + returnValueForMissingStub: _i3.Stream>.empty(), + ) + as _i3.Stream>); + + @override + _i3.Future updateTodo(_i4.TodoEntity? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); +} diff --git a/mvi_base/test/user_interactor_test.dart b/mvi_base/test/user_interactor_test.dart index 37ea1a19..6d88cf0c 100644 --- a/mvi_base/test/user_interactor_test.dart +++ b/mvi_base/test/user_interactor_test.dart @@ -1,26 +1,27 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:mvi_base/mvi_base.dart'; import 'package:test/test.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; -class MockUserRepository extends Mock implements UserRepository {} +import 'user_interactor_test.mocks.dart'; +@GenerateNiceMocks([MockSpec()]) void main() { group('UserInteractor', () { test('should convert repo entities into Todos', () async { final repository = MockUserRepository(); final interactor = UserInteractor(repository); - when(repository.login()) - .thenAnswer((_) => Future.value(UserEntity(displayName: 'Frida'))); + when(repository.login()).thenAnswer( + (_) => Future.value( + UserEntity(displayName: 'Frida', id: '', photoUrl: ''), + ), + ); - expect(await interactor.login(), User('Frida')); + expect(await interactor.login(), User(displayName: 'Frida')); }); }); } diff --git a/mvi_base/test/user_interactor_test.mocks.dart b/mvi_base/test/user_interactor_test.mocks.dart new file mode 100644 index 00000000..bfb23b3a --- /dev/null +++ b/mvi_base/test/user_interactor_test.mocks.dart @@ -0,0 +1,48 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in mvi_base/test/user_interactor_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:todos_repository_core/src/user_entity.dart' as _i2; +import 'package:todos_repository_core/src/user_repository.dart' as _i3; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member + +class _FakeUserEntity_0 extends _i1.SmartFake implements _i2.UserEntity { + _FakeUserEntity_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [UserRepository]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockUserRepository extends _i1.Mock implements _i3.UserRepository { + @override + _i4.Future<_i2.UserEntity> login() => + (super.noSuchMethod( + Invocation.method(#login, []), + returnValue: _i4.Future<_i2.UserEntity>.value( + _FakeUserEntity_0(this, Invocation.method(#login, [])), + ), + returnValueForMissingStub: _i4.Future<_i2.UserEntity>.value( + _FakeUserEntity_0(this, Invocation.method(#login, [])), + ), + ) + as _i4.Future<_i2.UserEntity>); +} diff --git a/mvi_flutter/.metadata b/mvi_flutter/.metadata index 1b5cec02..05a8ab44 100644 --- a/mvi_flutter/.metadata +++ b/mvi_flutter/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: 27321ebbad34b0a3fafe99fac037102196d655ff - channel: stable + revision: "05db9689081f091050f01aed79f04dce0c750154" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: android + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: ios + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: linux + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: macos + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: web + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: windows + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/mvi_flutter/analysis_options.yaml b/mvi_flutter/analysis_options.yaml new file mode 100644 index 00000000..134f2137 --- /dev/null +++ b/mvi_flutter/analysis_options.yaml @@ -0,0 +1,34 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# 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 +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + # The lint rules applied to this project can be customized in the + # 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 + # and their documentation is published at https://dart.dev/lints. + # + # 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 + # 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 + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/mvi_flutter/android/.gitignore b/mvi_flutter/android/.gitignore index bc2100d8..be3943c9 100644 --- a/mvi_flutter/android/.gitignore +++ b/mvi_flutter/android/.gitignore @@ -5,3 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/mvi_flutter/android/app/build.gradle b/mvi_flutter/android/app/build.gradle deleted file mode 100644 index fda8349b..00000000 --- a/mvi_flutter/android/app/build.gradle +++ /dev/null @@ -1,68 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.mvi_flutter" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - multiDexEnabled true - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/mvi_flutter/android/app/build.gradle.kts b/mvi_flutter/android/app/build.gradle.kts new file mode 100644 index 00000000..e9bcedb0 --- /dev/null +++ b/mvi_flutter/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.mvi_flutter_sample" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.mvi_flutter_sample" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/mvi_flutter/android/app/src/debug/AndroidManifest.xml b/mvi_flutter/android/app/src/debug/AndroidManifest.xml index 3a0d609d..399f6981 100644 --- a/mvi_flutter/android/app/src/debug/AndroidManifest.xml +++ b/mvi_flutter/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/mvi_flutter/android/app/src/main/AndroidManifest.xml b/mvi_flutter/android/app/src/main/AndroidManifest.xml index b16c8962..7fa5a973 100644 --- a/mvi_flutter/android/app/src/main/AndroidManifest.xml +++ b/mvi_flutter/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,25 @@ - - + + + @@ -27,4 +31,15 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + diff --git a/mvi_flutter/android/app/src/main/kotlin/com/example/mvi_flutter/MainActivity.kt b/mvi_flutter/android/app/src/main/kotlin/com/example/mvi_flutter/MainActivity.kt deleted file mode 100644 index 8ed35f5d..00000000 --- a/mvi_flutter/android/app/src/main/kotlin/com/example/mvi_flutter/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.mvi_flutter - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/mvi_flutter/android/app/src/main/kotlin/com/example/mvi_flutter_sample/MainActivity.kt b/mvi_flutter/android/app/src/main/kotlin/com/example/mvi_flutter_sample/MainActivity.kt new file mode 100644 index 00000000..06249821 --- /dev/null +++ b/mvi_flutter/android/app/src/main/kotlin/com/example/mvi_flutter_sample/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.mvi_flutter_sample + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/mvi_flutter/android/app/src/main/res/drawable-v21/launch_background.xml b/mvi_flutter/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/mvi_flutter/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/mvi_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/mvi_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index a3f285f9..db77bb4b 100644 Binary files a/mvi_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/mvi_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/mvi_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/mvi_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 5e6f3ac6..17987b79 100644 Binary files a/mvi_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/mvi_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/mvi_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/mvi_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 144d60be..09d43914 100644 Binary files a/mvi_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/mvi_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/mvi_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/mvi_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index deafae2d..d5f1c8d3 100644 Binary files a/mvi_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/mvi_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/mvi_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/mvi_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index d5614ac8..4d6372ee 100644 Binary files a/mvi_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/mvi_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/mvi_flutter/android/app/src/main/res/values-night/styles.xml b/mvi_flutter/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/mvi_flutter/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/mvi_flutter/android/app/src/main/res/values/styles.xml b/mvi_flutter/android/app/src/main/res/values/styles.xml index 00fa4417..cb1ef880 100644 --- a/mvi_flutter/android/app/src/main/res/values/styles.xml +++ b/mvi_flutter/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ - + + diff --git a/mvi_flutter/android/app/src/profile/AndroidManifest.xml b/mvi_flutter/android/app/src/profile/AndroidManifest.xml index 3a0d609d..399f6981 100644 --- a/mvi_flutter/android/app/src/profile/AndroidManifest.xml +++ b/mvi_flutter/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/mvi_flutter/android/build.gradle b/mvi_flutter/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/mvi_flutter/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/mvi_flutter/android/build.gradle.kts b/mvi_flutter/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/mvi_flutter/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/mvi_flutter/android/gradle.properties b/mvi_flutter/android/gradle.properties index 38c8d454..f018a618 100644 --- a/mvi_flutter/android/gradle.properties +++ b/mvi_flutter/android/gradle.properties @@ -1,4 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/mvi_flutter/android/gradle/wrapper/gradle-wrapper.properties b/mvi_flutter/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..ac3b4792 100644 --- a/mvi_flutter/android/gradle/wrapper/gradle-wrapper.properties +++ b/mvi_flutter/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/mvi_flutter/android/settings.gradle b/mvi_flutter/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/mvi_flutter/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/mvi_flutter/android/settings.gradle.kts b/mvi_flutter/android/settings.gradle.kts new file mode 100644 index 00000000..fb605bc8 --- /dev/null +++ b/mvi_flutter/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/mvi_flutter/integration_test/app_test.dart b/mvi_flutter/integration_test/app_test.dart new file mode 100644 index 00000000..5292d703 --- /dev/null +++ b/mvi_flutter/integration_test/app_test.dart @@ -0,0 +1,26 @@ +import 'package:integration_tests/integration_tests.dart' as integration_tests; +import 'package:mvi_base/mvi_base.dart'; +import 'package:mvi_flutter_sample/anonymous_user_repository.dart'; +import 'package:mvi_flutter_sample/mvi_app.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; + +void main() { + integration_tests.run( + appBuilder: () async { + return MviApp( + todoListInteractor: TodoListInteractor( + ReactiveLocalStorageRepository( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'mvi_flutter_test_${DateTime.now().toIso8601String()}', + await SharedPreferences.getInstance(), + ), + ), + ), + ), + userInteractor: UserInteractor(AnonymousUserRepository()), + ); + }, + ); +} diff --git a/mvi_flutter/ios/.gitignore b/mvi_flutter/ios/.gitignore index e96ef602..7a7f9873 100644 --- a/mvi_flutter/ios/.gitignore +++ b/mvi_flutter/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/mvi_flutter/ios/Flutter/AppFrameworkInfo.plist b/mvi_flutter/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f78..1dc6cf76 100644 --- a/mvi_flutter/ios/Flutter/AppFrameworkInfo.plist +++ b/mvi_flutter/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 13.0 diff --git a/mvi_flutter/ios/Flutter/Debug.xcconfig b/mvi_flutter/ios/Flutter/Debug.xcconfig index e8efba11..ec97fc6f 100644 --- a/mvi_flutter/ios/Flutter/Debug.xcconfig +++ b/mvi_flutter/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/mvi_flutter/ios/Flutter/Release.xcconfig b/mvi_flutter/ios/Flutter/Release.xcconfig index 399e9340..c4855bfe 100644 --- a/mvi_flutter/ios/Flutter/Release.xcconfig +++ b/mvi_flutter/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/mvi_flutter/ios/Podfile b/mvi_flutter/ios/Podfile index b30a428b..620e46eb 100644 --- a/mvi_flutter/ios/Podfile +++ b/mvi_flutter/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -10,81 +10,34 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - generated_key_values + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' +flutter_ios_podfile_setup - # Plugin Pods +target 'Runner' do + use_frameworks! - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths end end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/mvi_flutter/ios/Runner.xcodeproj/project.pbxproj b/mvi_flutter/ios/Runner.xcodeproj/project.pbxproj index f7a07b0b..47a28a21 100644 --- a/mvi_flutter/ios/Runner.xcodeproj/project.pbxproj +++ b/mvi_flutter/ios/Runner.xcodeproj/project.pbxproj @@ -3,23 +3,29 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 4EEE3E9323C493FB0065A5A2 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4EEE3E9223C493FB0065A5A2 /* GoogleService-Info.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -27,8 +33,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -38,15 +42,14 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 4EEE3E9223C493FB0065A5A2 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -59,20 +62,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -86,6 +93,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -93,6 +101,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -100,12 +109,10 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( - 4EEE3E9223C493FB0065A5A2 /* GoogleService-Info.plist */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -114,16 +121,26 @@ path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; @@ -150,9 +167,14 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -160,7 +182,7 @@ }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -173,18 +195,25 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 4EEE3E9323C493FB0065A5A2 /* GoogleService-Info.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); @@ -195,20 +224,23 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -224,6 +256,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -235,6 +275,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -257,9 +305,9 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -289,6 +337,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -297,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -313,18 +362,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutter; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutterSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -332,11 +377,58 @@ }; name = Profile; }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -366,6 +458,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -380,7 +473,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -390,9 +483,9 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -422,6 +515,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -430,11 +524,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -447,18 +542,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutter; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutterSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -474,18 +565,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutter; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutterSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -496,6 +583,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/mvi_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mvi_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/mvi_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/mvi_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/mvi_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mvi_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/mvi_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/mvi_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/mvi_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/mvi_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/mvi_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/mvi_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..e3773d42 100644 --- a/mvi_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/mvi_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + + + + + @@ -61,8 +73,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - + + + + IDEDidComputeMac32BitWarning + + + diff --git a/mvi_flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/mvi_flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/mvi_flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/mvi_flutter/ios/Runner/AppDelegate.swift b/mvi_flutter/ios/Runner/AppDelegate.swift index 70693e4a..62666446 100644 --- a/mvi_flutter/ios/Runner/AppDelegate.swift +++ b/mvi_flutter/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ -import UIKit import Flutter +import UIKit -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d22f10b2..d36b1fab 100644 --- a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -107,6 +107,12 @@ "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" } ], "info" : { diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 980e5ad6..7353c41e 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index fd870289..797d452e 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 75e84cd1..6ed2d933 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 03ab8a84..4cd7b009 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index a03431cb..fe730945 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index f47613ee..321773cd 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 7f2230a9..797d452e 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 42315c6d..502f463a 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index f9882cc0..0ec30343 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 45537513..0ec30343 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 6360ea17..e9f5fea2 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 152d5e12..84ac32ae 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 310b0b8f..8953cba0 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 092b7bfe..0467bf12 100644 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/mvi_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/mvi_flutter/ios/Runner/GoogleService-Info.plist b/mvi_flutter/ios/Runner/GoogleService-Info.plist deleted file mode 100644 index c8cc9bf9..00000000 --- a/mvi_flutter/ios/Runner/GoogleService-Info.plist +++ /dev/null @@ -1,40 +0,0 @@ - - - - - AD_UNIT_ID_FOR_BANNER_TEST - ca-app-pub-9999999999999999/9999999999 - AD_UNIT_ID_FOR_INTERSTITIAL_TEST - ca-app-pub-9999999999999999/9999999999 - CLIENT_ID - xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com - REVERSED_CLIENT_ID - com.googleusercontent.apps.xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - API_KEY - xxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx - GCM_SENDER_ID - 999999999999 - PLIST_VERSION - 1 - BUNDLE_ID - com.fluttersamples.bloc - PROJECT_ID - xxxxxxxxxxxxx-99999 - STORAGE_BUCKET - xxxxxxxxxxxxx-99999.appspot.com - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 9:999999999999:ios:xxxxxxxxxxxxxxxx - DATABASE_URL - https://xxxxxxxxxxxxx-99999.firebaseio.com - - \ No newline at end of file diff --git a/mvi_flutter/ios/Runner/Info.plist b/mvi_flutter/ios/Runner/Info.plist index d07a5a48..40e5f3ef 100644 --- a/mvi_flutter/ios/Runner/Info.plist +++ b/mvi_flutter/ios/Runner/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Mvi Flutter Sample CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -11,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - mvi_flutter + mvi_flutter_sample CFBundlePackageType APPL CFBundleShortVersionString @@ -39,7 +41,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/mvi_flutter/ios/Runner/Runner-Bridging-Header.h b/mvi_flutter/ios/Runner/Runner-Bridging-Header.h index 7335fdf9..308a2a56 100644 --- a/mvi_flutter/ios/Runner/Runner-Bridging-Header.h +++ b/mvi_flutter/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file +#import "GeneratedPluginRegistrant.h" diff --git a/mvi_flutter/ios/RunnerTests/RunnerTests.swift b/mvi_flutter/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/mvi_flutter/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/mvi_flutter/lib/anonymous_user_repository.dart b/mvi_flutter/lib/anonymous_user_repository.dart new file mode 100644 index 00000000..538b88c1 --- /dev/null +++ b/mvi_flutter/lib/anonymous_user_repository.dart @@ -0,0 +1,10 @@ +import 'package:todos_repository_core/todos_repository_core.dart'; + +class AnonymousUserRepository implements UserRepository { + @override + Future login() { + return Future.value( + UserEntity(id: 'anonymous', displayName: '', photoUrl: ''), + ); + } +} diff --git a/mvi_flutter/lib/dependency_injection.dart b/mvi_flutter/lib/dependency_injection.dart index a2977dd3..0f00df8f 100644 --- a/mvi_flutter/lib/dependency_injection.dart +++ b/mvi_flutter/lib/dependency_injection.dart @@ -1,28 +1,19 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// A poor man's DI. This should be replaced by a proper solution once they -// are more stable. -library dependency_injector; - import 'package:flutter/widgets.dart'; -import 'package:meta/meta.dart'; import 'package:mvi_base/mvi_base.dart'; class Injector extends InheritedWidget { - final TodosInteractor todosInteractor; + final TodoListInteractor todosInteractor; final UserInteractor userInteractor; - Injector({ - Key key, - @required this.todosInteractor, - @required this.userInteractor, - @required Widget child, - }) : super(key: key, child: child); + const Injector({ + super.key, + required this.todosInteractor, + required this.userInteractor, + required super.child, + }); static Injector of(BuildContext context) => - context.dependOnInheritedWidgetOfExactType(); + context.dependOnInheritedWidgetOfExactType()!; @override bool updateShouldNotify(Injector oldWidget) => diff --git a/mvi_flutter/lib/localization.dart b/mvi_flutter/lib/localization.dart index 30b45c3c..ce625bc3 100644 --- a/mvi_flutter/lib/localization.dart +++ b/mvi_flutter/lib/localization.dart @@ -1,14 +1,10 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; class BlocLocalizations { static BlocLocalizations of(BuildContext context) { - return Localizations.of(context, BlocLocalizations); + return Localizations.of(context, BlocLocalizations)!; } String get appTitle => 'MVI Example'; diff --git a/mvi_flutter/lib/main.dart b/mvi_flutter/lib/main.dart index cfd941e7..b31ffbeb 100644 --- a/mvi_flutter/lib/main.dart +++ b/mvi_flutter/lib/main.dart @@ -1,38 +1,28 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/widgets.dart'; -import 'package:key_value_store_flutter/key_value_store_flutter.dart'; import 'package:mvi_base/mvi_base.dart'; +import 'package:mvi_flutter_sample/anonymous_user_repository.dart'; import 'package:mvi_flutter_sample/mvi_app.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(MviApp( - todosRepository: TodosInteractor( - ReactiveLocalStorageRepository( - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'mvi_flutter', - FlutterKeyValueStore(await SharedPreferences.getInstance()), + runApp( + MviApp( + todoListInteractor: TodoListInteractor( + ReactiveLocalStorageRepository( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'mvi_flutter_sample', + await SharedPreferences.getInstance(), + ), ), ), ), + userInteractor: UserInteractor(AnonymousUserRepository()), ), - userInteractor: UserInteractor(AnonymousUserRepository()), - )); -} - -class AnonymousUserRepository implements UserRepository { - @override - Future login() { - return Future.value(UserEntity(id: 'anonymous')); - } + ); } diff --git a/mvi_flutter/lib/main_firebase.dart b/mvi_flutter/lib/main_firebase.dart deleted file mode 100644 index 9fb15b32..00000000 --- a/mvi_flutter/lib/main_firebase.dart +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:firebase_flutter_repository/reactive_todos_repository.dart'; -import 'package:firebase_flutter_repository/user_repository.dart'; -import 'package:flutter/widgets.dart'; -import 'package:mvi_base/mvi_base.dart'; -import 'package:mvi_flutter_sample/mvi_app.dart'; - -void main() { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(MviApp( - todosRepository: TodosInteractor( - FirestoreReactiveTodosRepository(Firestore.instance), - ), - userInteractor: UserInteractor( - FirebaseUserRepository(FirebaseAuth.instance), - ), - )); -} diff --git a/mvi_flutter/lib/main_web.dart b/mvi_flutter/lib/main_web.dart deleted file mode 100644 index 1e80f1dd..00000000 --- a/mvi_flutter/lib/main_web.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; -import 'dart:html'; - -import 'package:flutter/widgets.dart'; -import 'package:key_value_store_web/key_value_store_web.dart'; -import 'package:mvi_base/mvi_base.dart'; -import 'package:mvi_flutter_sample/mvi_app.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(MviApp( - todosRepository: TodosInteractor( - ReactiveLocalStorageRepository( - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'mvi_flutter', - WebKeyValueStore(window.localStorage), - ), - ), - ), - ), - userInteractor: UserInteractor(AnonymousUserRepository()), - )); -} - -class AnonymousUserRepository implements UserRepository { - @override - Future login() { - return Future.value(UserEntity(id: 'anonymous')); - } -} diff --git a/mvi_flutter/lib/mvi_app.dart b/mvi_flutter/lib/mvi_app.dart index aea74421..4240c205 100644 --- a/mvi_flutter/lib/mvi_app.dart +++ b/mvi_flutter/lib/mvi_app.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:mvi_base/mvi_base.dart'; import 'package:mvi_flutter_sample/dependency_injection.dart'; @@ -11,20 +7,24 @@ import 'package:mvi_flutter_sample/screens/home_screen.dart'; import 'package:todos_app_core/todos_app_core.dart'; class MviApp extends StatelessWidget { - final TodosInteractor todosRepository; + final TodoListInteractor todoListInteractor; final UserInteractor userInteractor; - const MviApp({Key key, this.todosRepository, this.userInteractor}) - : super(key: key); + const MviApp({ + super.key, + required this.todoListInteractor, + required this.userInteractor, + }); @override Widget build(BuildContext context) { return Injector( - todosInteractor: todosRepository, + todosInteractor: todoListInteractor, userInteractor: userInteractor, child: MaterialApp( onGenerateTitle: (context) => BlocLocalizations.of(context).appTitle, - theme: ArchSampleTheme.theme, + theme: ArchSampleTheme.lightTheme, + darkTheme: ArchSampleTheme.darkTheme, localizationsDelegates: [ ArchSampleLocalizationsDelegate(), InheritedWidgetLocalizationsDelegate(), diff --git a/mvi_flutter/lib/screens/add_edit_screen.dart b/mvi_flutter/lib/screens/add_edit_screen.dart index 589487fa..bb4e2617 100644 --- a/mvi_flutter/lib/screens/add_edit_screen.dart +++ b/mvi_flutter/lib/screens/add_edit_screen.dart @@ -1,34 +1,28 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:mvi_base/mvi_base.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class AddEditScreen extends StatefulWidget { - final Todo todo; - final Function(Todo) addTodo; - final Function(Todo) updateTodo; + final Todo? todo; + final void Function(Todo)? addTodo; + final void Function(Todo)? updateTodo; - AddEditScreen({ - Key key, - this.todo, + const AddEditScreen({ + super.key = ArchSampleKeys.addTodoScreen, this.addTodo, this.updateTodo, - }) : super(key: key ?? ArchSampleKeys.addTodoScreen); + this.todo, + }); @override - _AddEditScreenState createState() => _AddEditScreenState(); + AddEditScreenState createState() => AddEditScreenState(); } -class _AddEditScreenState extends State { +class AddEditScreenState extends State { static final GlobalKey formKey = GlobalKey(); - String _task; - String _note; + late String _task; + late String _note; @override Widget build(BuildContext context) { @@ -44,58 +38,56 @@ class _AddEditScreenState extends State { padding: EdgeInsets.all(16.0), child: Form( key: formKey, - autovalidate: false, - onWillPop: () { - return Future(() => true); - }, + autovalidateMode: AutovalidateMode.always, + canPop: true, child: ListView( children: [ TextFormField( - initialValue: widget.todo != null ? widget.todo.task : '', + initialValue: isEditing ? widget.todo!.task : '', key: ArchSampleKeys.taskField, autofocus: isEditing ? false : true, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, decoration: InputDecoration( hintText: ArchSampleLocalizations.of(context).newTodoHint, ), - validator: (val) => val.trim().isEmpty + validator: (val) => val != null && val.trim().isEmpty ? ArchSampleLocalizations.of(context).emptyTodoError : null, - onSaved: (value) => _task = value, + onSaved: (value) => _task = value ?? '', ), TextFormField( - initialValue: widget.todo != null ? widget.todo.note : '', + initialValue: isEditing ? widget.todo!.note : '', key: ArchSampleKeys.noteField, maxLines: 10, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, decoration: InputDecoration( hintText: ArchSampleLocalizations.of(context).notesHint, ), - onSaved: (value) => _note = value, - ) + onSaved: (value) => _note = value ?? '', + ), ], ), ), ), floatingActionButton: FloatingActionButton( - key: - isEditing ? ArchSampleKeys.saveTodoFab : ArchSampleKeys.saveNewTodo, + key: isEditing + ? ArchSampleKeys.saveTodoFab + : ArchSampleKeys.saveNewTodo, tooltip: isEditing ? ArchSampleLocalizations.of(context).saveChanges : ArchSampleLocalizations.of(context).addTodo, child: Icon(isEditing ? Icons.check : Icons.add), onPressed: () { final form = formKey.currentState; - if (form.validate()) { + if (form!.validate()) { form.save(); if (isEditing) { - widget.updateTodo(widget.todo.copyWith(task: _task, note: _note)); + widget.updateTodo!( + widget.todo!.copyWith(task: _task, note: _note), + ); } else { - widget.addTodo(Todo( - _task, - note: _note, - )); + widget.addTodo!(Todo(_task, note: _note)); } Navigator.pop(context); diff --git a/mvi_flutter/lib/screens/detail_screen.dart b/mvi_flutter/lib/screens/detail_screen.dart index 535f1165..f076b0fc 100644 --- a/mvi_flutter/lib/screens/detail_screen.dart +++ b/mvi_flutter/lib/screens/detail_screen.dart @@ -1,24 +1,19 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:mvi_base/mvi_base.dart'; import 'package:mvi_flutter_sample/dependency_injection.dart'; import 'package:mvi_flutter_sample/screens/add_edit_screen.dart'; import 'package:mvi_flutter_sample/widgets/loading.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class DetailScreen extends StatefulWidget { final String todoId; - final MviPresenter Function(DetailView) initPresenter; + final MviPresenter Function(DetailView)? initPresenter; - DetailScreen({ - Key key, - @required this.todoId, + const DetailScreen({ + super.key = ArchSampleKeys.todoDetailsScreen, + required this.todoId, this.initPresenter, - }) : super(key: key ?? ArchSampleKeys.todoDetailsScreen); + }); @override DetailScreenState createState() { @@ -27,12 +22,12 @@ class DetailScreen extends StatefulWidget { } class DetailScreenState extends State with DetailView { - MviPresenter presenter; + late final MviPresenter presenter; @override void didChangeDependencies() { presenter = widget.initPresenter != null - ? widget.initPresenter(this) + ? widget.initPresenter!(this) : DetailPresenter( id: widget.todoId, view: this, @@ -54,11 +49,11 @@ class DetailScreenState extends State with DetailView { @override Widget build(BuildContext context) { return StreamBuilder( - stream: presenter.where((todo) => todo != null), + stream: presenter, builder: (context, snapshot) { if (!snapshot.hasData) return LoadingSpinner(); - final todo = snapshot.data; + final todo = snapshot.data!; return Scaffold( appBar: AppBar( @@ -72,7 +67,7 @@ class DetailScreenState extends State with DetailView { deleteTodo.add(todo.id); Navigator.pop(context, todo); }, - ) + ), ], ), body: Padding( @@ -88,8 +83,9 @@ class DetailScreenState extends State with DetailView { value: todo.complete, key: ArchSampleKeys.detailsTodoItemCheckbox, onChanged: (complete) { - updateTodo - .add(todo.copyWith(complete: !todo.complete)); + updateTodo.add( + todo.copyWith(complete: !todo.complete), + ); }, ), ), @@ -98,21 +94,18 @@ class DetailScreenState extends State with DetailView { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), + padding: EdgeInsets.only(top: 8.0, bottom: 16.0), child: Text( todo.task, key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, ), ), Text( todo.note, key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) + style: Theme.of(context).textTheme.titleMedium, + ), ], ), ), @@ -123,11 +116,10 @@ class DetailScreenState extends State with DetailView { ), floatingActionButton: FloatingActionButton( tooltip: ArchSampleLocalizations.of(context).editTodo, - child: Icon(Icons.edit), key: ArchSampleKeys.editTodoFab, onPressed: () { Navigator.of(context).push( - MaterialPageRoute( + MaterialPageRoute( builder: (context) { return AddEditScreen( todo: todo, @@ -138,6 +130,7 @@ class DetailScreenState extends State with DetailView { ), ); }, + child: Icon(Icons.edit), ), ); }, diff --git a/mvi_flutter/lib/screens/home_screen.dart b/mvi_flutter/lib/screens/home_screen.dart index acfd63ca..e8149807 100644 --- a/mvi_flutter/lib/screens/home_screen.dart +++ b/mvi_flutter/lib/screens/home_screen.dart @@ -1,9 +1,4 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:mvi_base/mvi_base.dart'; import 'package:mvi_flutter_sample/dependency_injection.dart'; import 'package:mvi_flutter_sample/localization.dart'; @@ -12,30 +7,30 @@ import 'package:mvi_flutter_sample/widgets/filter_button.dart'; import 'package:mvi_flutter_sample/widgets/loading.dart'; import 'package:mvi_flutter_sample/widgets/stats_counter.dart'; import 'package:mvi_flutter_sample/widgets/todo_list.dart'; +import 'package:todos_app_core/todos_app_core.dart'; enum AppTab { todos, stats } class HomeScreen extends StatefulWidget { - final MviPresenter Function(TodosListView) initPresenter; + final TodoListPresenter Function(TodoListView)? initPresenter; - HomeScreen({Key key, this.initPresenter}) - : super(key: key ?? ArchSampleKeys.homeScreen); + const HomeScreen({super.key = ArchSampleKeys.homeScreen, this.initPresenter}); @override - State createState() { + State createState() { return HomeScreenState(); } } -class HomeScreenState extends State with TodosListView { +class HomeScreenState extends State with TodoListView { AppTab activeTab = AppTab.todos; - TodosListPresenter presenter; + late final TodoListPresenter presenter; @override void didChangeDependencies() { presenter = widget.initPresenter != null - ? widget.initPresenter(this) - : TodosListPresenter( + ? widget.initPresenter!(this) + : TodoListPresenter( view: this, todosInteractor: Injector.of(context).todosInteractor, userInteractor: Injector.of(context).userInteractor, @@ -55,24 +50,24 @@ class HomeScreenState extends State with TodosListView { @override Widget build(BuildContext context) { - return StreamBuilder( + return StreamBuilder( stream: presenter, initialData: presenter.latest, builder: (context, modelSnapshot) { + final data = modelSnapshot.data!; + return Scaffold( appBar: AppBar( title: Text(BlocLocalizations.of(context).appTitle), actions: [ FilterButton( isActive: activeTab == AppTab.todos, - activeFilter: - modelSnapshot.data?.activeFilter ?? VisibilityFilter.all, + activeFilter: data.activeFilter, onSelected: updateFilter.add, ), ExtraActionsButton( - allComplete: modelSnapshot.data?.allComplete ?? false, - hasCompletedTodos: - modelSnapshot.data?.hasCompletedTodos ?? false, + allComplete: data.allComplete, + hasCompletedTodos: data.hasCompletedTodos, onSelected: (action) { if (action == ExtraAction.toggleAllComplete) { toggleAll.add(null); @@ -83,26 +78,24 @@ class HomeScreenState extends State with TodosListView { ), ], ), - body: modelSnapshot.data.loading - ? LoadingSpinner( - key: ArchSampleKeys.todosLoading, - ) + body: data.loading + ? LoadingSpinner(key: ArchSampleKeys.todosLoading) : activeTab == AppTab.todos - ? TodoList( - loading: modelSnapshot.data.loading, - addTodo: addTodo.add, - updateTodo: updateTodo.add, - deleteTodo: deleteTodo.add, - todos: modelSnapshot.data?.visibleTodos ?? [], - ) - : StatsCounter(), + ? TodoList( + loading: data.loading, + addTodo: addTodo.add, + updateTodo: updateTodo.add, + deleteTodo: deleteTodo.add, + todos: data.visibleTodos, + ) + : StatsCounter(), floatingActionButton: FloatingActionButton( key: ArchSampleKeys.addTodoFab, onPressed: () { Navigator.pushNamed(context, ArchSampleRoutes.addTodo); }, - child: Icon(Icons.add), tooltip: ArchSampleLocalizations.of(context).addTodo, + child: Icon(Icons.add), ), bottomNavigationBar: BottomNavigationBar( key: ArchSampleKeys.tabs, @@ -120,11 +113,9 @@ class HomeScreenState extends State with TodosListView { ? ArchSampleKeys.statsTab : ArchSampleKeys.todoTab, ), - title: Text( - tab == AppTab.stats - ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos, - ), + label: tab == AppTab.stats + ? ArchSampleLocalizations.of(context).stats + : ArchSampleLocalizations.of(context).todos, ); }).toList(), ), diff --git a/mvi_flutter/lib/widgets/extra_actions_button.dart b/mvi_flutter/lib/widgets/extra_actions_button.dart index 1f6955b7..4449cb90 100644 --- a/mvi_flutter/lib/widgets/extra_actions_button.dart +++ b/mvi_flutter/lib/widgets/extra_actions_button.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; @@ -10,12 +6,12 @@ class ExtraActionsButton extends StatelessWidget { final bool allComplete; final bool hasCompletedTodos; - ExtraActionsButton({ - this.onSelected, + const ExtraActionsButton({ + super.key, + required this.onSelected, this.allComplete = false, this.hasCompletedTodos = true, - Key key, - }) : super(key: key); + }); @override Widget build(BuildContext context) { @@ -36,9 +32,7 @@ class ExtraActionsButton extends StatelessWidget { PopupMenuItem( key: ArchSampleKeys.clearCompleted, value: ExtraAction.clearCompleted, - child: Text( - ArchSampleLocalizations.of(context).clearCompleted, - ), + child: Text(ArchSampleLocalizations.of(context).clearCompleted), ), ]; }, diff --git a/mvi_flutter/lib/widgets/filter_button.dart b/mvi_flutter/lib/widgets/filter_button.dart index dab3f906..e36c7593 100644 --- a/mvi_flutter/lib/widgets/filter_button.dart +++ b/mvi_flutter/lib/widgets/filter_button.dart @@ -1,25 +1,24 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:mvi_base/mvi_base.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class FilterButton extends StatelessWidget { final PopupMenuItemSelected onSelected; final VisibilityFilter activeFilter; final bool isActive; - FilterButton({this.onSelected, this.activeFilter, this.isActive, Key key}) - : super(key: key); + const FilterButton({ + super.key, + required this.onSelected, + required this.activeFilter, + required this.isActive, + }); @override Widget build(BuildContext context) { - final theme = Theme.of(context); - final defaultStyle = theme.textTheme.body1; - final activeStyle = theme.textTheme.body1.copyWith( - color: theme.accentColor, + final defaultStyle = Theme.of(context).textTheme.bodyMedium!; + final activeStyle = defaultStyle.copyWith( + color: Theme.of(context).colorScheme.secondary, ); final button = _Button( onSelected: onSelected, @@ -38,12 +37,11 @@ class FilterButton extends StatelessWidget { class _Button extends StatelessWidget { const _Button({ - Key key, - @required this.onSelected, - @required this.activeFilter, - @required this.activeStyle, - @required this.defaultStyle, - }) : super(key: key); + required this.onSelected, + required this.activeFilter, + required this.activeStyle, + required this.defaultStyle, + }); final PopupMenuItemSelected onSelected; final VisibilityFilter activeFilter; diff --git a/mvi_flutter/lib/widgets/loading.dart b/mvi_flutter/lib/widgets/loading.dart index 0fa4416a..68c0ec55 100644 --- a/mvi_flutter/lib/widgets/loading.dart +++ b/mvi_flutter/lib/widgets/loading.dart @@ -1,16 +1,10 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; class LoadingSpinner extends StatelessWidget { - LoadingSpinner({Key key}) : super(key: key); + const LoadingSpinner({super.key}); @override Widget build(BuildContext context) { - return Center( - child: CircularProgressIndicator(), - ); + return Center(child: CircularProgressIndicator()); } } diff --git a/mvi_flutter/lib/widgets/stats_counter.dart b/mvi_flutter/lib/widgets/stats_counter.dart index 1804c569..ebaabcfb 100644 --- a/mvi_flutter/lib/widgets/stats_counter.dart +++ b/mvi_flutter/lib/widgets/stats_counter.dart @@ -1,19 +1,15 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:mvi_base/mvi_base.dart'; import 'package:mvi_flutter_sample/dependency_injection.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class StatsCounter extends StatefulWidget { - final MviPresenter Function() initPresenter; + final MviPresenter Function()? initPresenter; - StatsCounter({Key key, this.initPresenter}) - : super(key: key ?? ArchSampleKeys.statsCounter); + const StatsCounter({ + super.key = ArchSampleKeys.statsCounter, + this.initPresenter, + }); @override StatsCounterState createState() { @@ -22,12 +18,12 @@ class StatsCounter extends StatefulWidget { } class StatsCounterState extends State { - StatsPresenter presenter; + late final MviPresenter presenter; @override void didChangeDependencies() { presenter = widget.initPresenter != null - ? widget.initPresenter() + ? widget.initPresenter!() : StatsPresenter(Injector.of(context).todosInteractor); presenter.setUp(); @@ -47,43 +43,50 @@ class StatsCounterState extends State { stream: presenter, initialData: presenter.latest, builder: (context, snapshot) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '${snapshot.data?.numComplete ?? 0}', - key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, - ), + final data = snapshot.data!; + + switch (data) { + case StatsModelLoading(): + return const SizedBox.shrink(); + case StatsModelLoaded(): + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 8.0), + child: Text( + ArchSampleLocalizations.of(context).completedTodos, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + Padding( + padding: EdgeInsets.only(bottom: 24.0), + child: Text( + '${data.numComplete}', + key: ArchSampleKeys.statsNumCompleted, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + Padding( + padding: EdgeInsets.only(bottom: 8.0), + child: Text( + ArchSampleLocalizations.of(context).activeTodos, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + Padding( + padding: EdgeInsets.only(bottom: 24.0), + child: Text( + '${data.numActive}', + key: ArchSampleKeys.statsNumActive, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ], ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '${snapshot.data?.numActive ?? 0}', - key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, - ), - ) - ], - ), - ); + ); + } }, ); } diff --git a/mvi_flutter/lib/widgets/todo_item.dart b/mvi_flutter/lib/widgets/todo_item.dart index 91490780..eb3c324b 100644 --- a/mvi_flutter/lib/widgets/todo_item.dart +++ b/mvi_flutter/lib/widgets/todo_item.dart @@ -1,23 +1,19 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:mvi_base/mvi_base.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class TodoItem extends StatelessWidget { final DismissDirectionCallback onDismissed; final GestureTapCallback onTap; - final ValueChanged onCheckboxChanged; + final ValueChanged onCheckboxChanged; final Todo todo; - TodoItem({ - @required this.onDismissed, - @required this.onTap, - @required this.onCheckboxChanged, - @required this.todo, + const TodoItem({ + super.key, + required this.onDismissed, + required this.onTap, + required this.onCheckboxChanged, + required this.todo, }); @override @@ -35,14 +31,14 @@ class TodoItem extends StatelessWidget { title: Text( todo.task, key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), subtitle: Text( todo.note, key: ArchSampleKeys.todoItemNote(todo.id), maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ); diff --git a/mvi_flutter/lib/widgets/todo_list.dart b/mvi_flutter/lib/widgets/todo_list.dart index eb447886..3964685d 100644 --- a/mvi_flutter/lib/widgets/todo_list.dart +++ b/mvi_flutter/lib/widgets/todo_list.dart @@ -1,30 +1,25 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:mvi_base/mvi_base.dart'; import 'package:mvi_flutter_sample/screens/detail_screen.dart'; import 'package:mvi_flutter_sample/widgets/loading.dart'; import 'package:mvi_flutter_sample/widgets/todo_item.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class TodoList extends StatelessWidget { final bool loading; final List todos; - final Function(Todo) updateTodo; - final Function(String) deleteTodo; - final Function(Todo) addTodo; + final void Function(Todo) updateTodo; + final void Function(String) deleteTodo; + final void Function(Todo) addTodo; - TodoList({ - Key key, - @required this.loading, - @required this.todos, - @required this.addTodo, - @required this.deleteTodo, - @required this.updateTodo, - }) : super(key: key); + const TodoList({ + super.key, + required this.loading, + required this.todos, + required this.addTodo, + required this.deleteTodo, + required this.updateTodo, + }); @override Widget build(BuildContext context) { @@ -46,17 +41,19 @@ class TodoList extends StatelessWidget { _removeTodo(context, todo); }, onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) { - return DetailScreen(todoId: todo.id); - }, - ), - ).then((todo) { - if (todo is Todo) { - _showUndoSnackbar(context, todo); - } - }); + Navigator.of(context) + .push( + MaterialPageRoute( + builder: (_) { + return DetailScreen(todoId: todo.id); + }, + ), + ) + .then((todo) { + if (todo is Todo && context.mounted) { + _showUndoSnackbar(context, todo); + } + }); }, onCheckboxChanged: (complete) { updateTodo(todo.copyWith(complete: !todo.complete)); @@ -73,23 +70,23 @@ class TodoList extends StatelessWidget { } void _showUndoSnackbar(BuildContext context, Todo todo) { - final snackBar = SnackBar( - key: ArchSampleKeys.snackbar, - duration: Duration(seconds: 2), - content: Text( - ArchSampleLocalizations.of(context).todoDeleted(todo.task), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - action: SnackBarAction( - key: ArchSampleKeys.snackbarAction(todo.id), - label: ArchSampleLocalizations.of(context).undo, - onPressed: () { - addTodo(todo); - }, + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + key: ArchSampleKeys.snackbar, + duration: Duration(seconds: 2), + content: Text( + ArchSampleLocalizations.of(context).todoDeleted(todo.task), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + action: SnackBarAction( + key: ArchSampleKeys.snackbarAction(todo.id), + label: ArchSampleLocalizations.of(context).undo, + onPressed: () { + addTodo(todo); + }, + ), ), ); - - Scaffold.of(context).showSnackBar(snackBar); } } diff --git a/mvi_flutter/linux/.gitignore b/mvi_flutter/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/mvi_flutter/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/mvi_flutter/linux/CMakeLists.txt b/mvi_flutter/linux/CMakeLists.txt new file mode 100644 index 00000000..7d4cb697 --- /dev/null +++ b/mvi_flutter/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +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 "mvi_flutter_sample") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.mvi_flutter_sample") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +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() + +# 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() + +# 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_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# 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 +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# 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() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +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) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/mvi_flutter/linux/flutter/CMakeLists.txt b/mvi_flutter/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/mvi_flutter/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +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. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# 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/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter 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. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/mvi_flutter/linux/flutter/generated_plugin_registrant.cc b/mvi_flutter/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e71a16d2 --- /dev/null +++ b/mvi_flutter/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/mvi_flutter/linux/flutter/generated_plugin_registrant.h b/mvi_flutter/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/mvi_flutter/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/mvi_flutter/linux/flutter/generated_plugins.cmake b/mvi_flutter/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/mvi_flutter/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + 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}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/mvi_flutter/linux/runner/CMakeLists.txt b/mvi_flutter/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/mvi_flutter/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "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 +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/mvi_flutter/linux/runner/main.cc b/mvi_flutter/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/mvi_flutter/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/mvi_flutter/linux/runner/my_application.cc b/mvi_flutter/linux/runner/my_application.cc new file mode 100644 index 00000000..64b95a05 --- /dev/null +++ b/mvi_flutter/linux/runner/my_application.cc @@ -0,0 +1,144 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView *view) +{ + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // 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 + // desktop). + // 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. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "mvi_flutter_sample"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "mvi_flutter_sample"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/mvi_flutter/linux/runner/my_application.h b/mvi_flutter/linux/runner/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/mvi_flutter/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/mvi_flutter/macos/.gitignore b/mvi_flutter/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/mvi_flutter/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/mvi_flutter/macos/Flutter/Flutter-Debug.xcconfig b/mvi_flutter/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/mvi_flutter/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/mvi_flutter/macos/Flutter/Flutter-Release.xcconfig b/mvi_flutter/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/mvi_flutter/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/mvi_flutter/macos/Flutter/GeneratedPluginRegistrant.swift b/mvi_flutter/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b8e2b22f --- /dev/null +++ b/mvi_flutter/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/mvi_flutter/macos/Podfile b/mvi_flutter/macos/Podfile new file mode 100644 index 00000000..ff5ddb3b --- /dev/null +++ b/mvi_flutter/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/mvi_flutter/macos/Podfile.lock b/mvi_flutter/macos/Podfile.lock new file mode 100644 index 00000000..d2f9a639 --- /dev/null +++ b/mvi_flutter/macos/Podfile.lock @@ -0,0 +1,30 @@ +PODS: + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + +SPEC CHECKSUMS: + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.16.2 diff --git a/mvi_flutter/macos/Runner.xcodeproj/project.pbxproj b/mvi_flutter/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..e1f0ff35 --- /dev/null +++ b/mvi_flutter/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 25C4AD941E8F454E82032FFF /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9ABA2C2189C72178160F73A7 /* Pods_RunnerTests.framework */; }; + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + EFDCF773E0A5EB24AA482411 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE8366489172ABD8876DCFF /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* mvi_flutter_sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = mvi_flutter_sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 3CE8366489172ABD8876DCFF /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 74000FD9F0C44CB23B769241 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 88ECB0501B418DC009DE9BFC /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 98082A639E70D4C9164C1ADA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 9ABA2C2189C72178160F73A7 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B82F95A2FC89558D5C046E7C /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + B888BC98DF982AED568EC8AA /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + FD36711DB5FE8EE91BCF4281 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 25C4AD941E8F454E82032FFF /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EFDCF773E0A5EB24AA482411 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 868D3F4F8530413CDE3C0F74 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* mvi_flutter_sample.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 868D3F4F8530413CDE3C0F74 /* Pods */ = { + isa = PBXGroup; + children = ( + 98082A639E70D4C9164C1ADA /* Pods-Runner.debug.xcconfig */, + FD36711DB5FE8EE91BCF4281 /* Pods-Runner.release.xcconfig */, + 88ECB0501B418DC009DE9BFC /* Pods-Runner.profile.xcconfig */, + 74000FD9F0C44CB23B769241 /* Pods-RunnerTests.debug.xcconfig */, + B888BC98DF982AED568EC8AA /* Pods-RunnerTests.release.xcconfig */, + B82F95A2FC89558D5C046E7C /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3CE8366489172ABD8876DCFF /* Pods_Runner.framework */, + 9ABA2C2189C72178160F73A7 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 7D151EEFCF088E77B136E20C /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 367B7DC2036FC00FEFFC54BB /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 4D34F133BFFF55C079356946 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* mvi_flutter_sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 367B7DC2036FC00FEFFC54BB /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 4D34F133BFFF55C079356946 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 7D151EEFCF088E77B136E20C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 74000FD9F0C44CB23B769241 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mvi_flutter_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mvi_flutter_sample"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B888BC98DF982AED568EC8AA /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mvi_flutter_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mvi_flutter_sample"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B82F95A2FC89558D5C046E7C /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mvi_flutter_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mvi_flutter_sample"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/mvi_flutter/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mvi_flutter/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/mvi_flutter/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/mvi_flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/mvi_flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..552ed934 --- /dev/null +++ b/mvi_flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mvi_flutter/macos/Runner.xcworkspace/contents.xcworkspacedata b/mvi_flutter/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/mvi_flutter/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/mvi_flutter/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mvi_flutter/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/mvi_flutter/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/mvi_flutter/macos/Runner/AppDelegate.swift b/mvi_flutter/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/mvi_flutter/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/mvi_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/mvi_flutter/macos/Runner/Base.lproj/MainMenu.xib b/mvi_flutter/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/mvi_flutter/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mvi_flutter/macos/Runner/Configs/AppInfo.xcconfig b/mvi_flutter/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..28932bba --- /dev/null +++ b/mvi_flutter/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// 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 +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = mvi_flutter_sample + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.mviFlutterSample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/mvi_flutter/macos/Runner/Configs/Debug.xcconfig b/mvi_flutter/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/mvi_flutter/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/mvi_flutter/macos/Runner/Configs/Release.xcconfig b/mvi_flutter/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/mvi_flutter/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/mvi_flutter/macos/Runner/Configs/Warnings.xcconfig b/mvi_flutter/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/mvi_flutter/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/mvi_flutter/macos/Runner/DebugProfile.entitlements b/mvi_flutter/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/mvi_flutter/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/mvi_flutter/macos/Runner/Info.plist b/mvi_flutter/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/mvi_flutter/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/mvi_flutter/macos/Runner/MainFlutterWindow.swift b/mvi_flutter/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/mvi_flutter/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/mvi_flutter/macos/Runner/Release.entitlements b/mvi_flutter/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/mvi_flutter/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/mvi_flutter/macos/RunnerTests/RunnerTests.swift b/mvi_flutter/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/mvi_flutter/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/mvi_flutter/pubspec.yaml b/mvi_flutter/pubspec.yaml index 2a9d57e4..4660f380 100644 --- a/mvi_flutter/pubspec.yaml +++ b/mvi_flutter/pubspec.yaml @@ -12,32 +12,33 @@ description: A new Flutter project. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html version: 1.0.0+1 +publish_to: "none" environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ^3.9.0 dependencies: flutter: sdk: flutter - todos_repository_local_storage: - path: ../todos_repository_local_storage - firebase_flutter_repository: - path: ../firebase_flutter_repository - todos_app_core: - path: ../todos_app_core mvi_base: path: ../mvi_base - rxdart: ^0.23.1 - key_value_store_flutter: - key_value_store_web: + rxdart: + rxdart_flutter: shared_preferences: + todos_app_core: + path: ../todos_app_core + todos_repository_core: + path: ../todos_repository_core + todos_repository_local_storage: + path: ../todos_repository_local_storage dev_dependencies: + build_runner: + flutter_lints: flutter_test: sdk: flutter - flutter_driver: + integration_test: sdk: flutter - test: integration_tests: path: ../integration_tests mockito: @@ -47,7 +48,6 @@ dev_dependencies: # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. diff --git a/mvi_flutter/test/detail_screen_test.dart b/mvi_flutter/test/detail_screen_test.dart index f0fdf077..14488515 100644 --- a/mvi_flutter/test/detail_screen_test.dart +++ b/mvi_flutter/test/detail_screen_test.dart @@ -1,15 +1,11 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; +import 'package:flutter_test/flutter_test.dart' as test; import 'package:flutter_test/flutter_test.dart'; import 'package:mvi_base/mvi_base.dart'; import 'package:mvi_flutter_sample/screens/detail_screen.dart'; -import 'package:test/test.dart' as test; +import 'package:todos_app_core/todos_app_core.dart'; void main() { test.group('DetailScreen', () { @@ -17,13 +13,8 @@ void main() { final todo = Todo('Hallo', note: 'Hello'); final presenter = MockDetailPresenter(todo); final screen = MaterialApp( - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - ], - home: DetailScreen( - todoId: todo.id, - initPresenter: (view) => presenter, - ), + localizationsDelegates: [ArchSampleLocalizationsDelegate()], + home: DetailScreen(todoId: todo.id, initPresenter: (view) => presenter), ); await tester.pumpWidget(screen); @@ -37,13 +28,8 @@ void main() { final todo = Todo('Hallo', note: 'Hello', complete: true); final presenter = MockDetailPresenter(todo); final screen = MaterialApp( - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - ], - home: DetailScreen( - todoId: todo.id, - initPresenter: (view) => presenter, - ), + localizationsDelegates: [ArchSampleLocalizationsDelegate()], + home: DetailScreen(todoId: todo.id, initPresenter: (view) => presenter), ); await tester.pumpWidget(screen); @@ -59,13 +45,8 @@ void main() { final todo = Todo('Hallo', note: 'Hello', complete: false); final presenter = MockDetailPresenter(todo); final screen = MaterialApp( - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - ], - home: DetailScreen( - todoId: todo.id, - initPresenter: (view) => presenter, - ), + localizationsDelegates: [ArchSampleLocalizationsDelegate()], + home: DetailScreen(todoId: todo.id, initPresenter: (view) => presenter), ); await tester.pumpWidget(screen); @@ -82,9 +63,7 @@ void main() { final presenter = MockDetailPresenter(todo); final key = GlobalKey(); final screen = MaterialApp( - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - ], + localizationsDelegates: [ArchSampleLocalizationsDelegate()], home: DetailScreen( key: key, todoId: todo.id, @@ -102,7 +81,7 @@ void main() { // Expect that the deleteTodoStream emits the current id. The Presenter // is responsible for listening to this stream and doing work with it! - expect(key.currentState.deleteTodo.stream, test.emits(todo.id)); + expect(key.currentState!.deleteTodo.stream, test.emits(todo.id)); }); testWidgets('should update a todo', (tester) async { @@ -110,9 +89,7 @@ void main() { final presenter = MockDetailPresenter(todo); final key = GlobalKey(); final screen = MaterialApp( - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - ], + localizationsDelegates: [ArchSampleLocalizationsDelegate()], home: DetailScreen( key: key, todoId: todo.id, @@ -131,7 +108,7 @@ void main() { // Expect that the deleteTodoStream emits the current id. The Presenter // is responsible for listening to this stream and doing work with it! expect( - key.currentState.updateTodo.stream, + key.currentState!.updateTodo.stream, test.emits(todo.copyWith(complete: true)), ); }); @@ -140,10 +117,7 @@ void main() { class MockDetailPresenter extends MviPresenter { MockDetailPresenter(Todo todo) - : super( - stream: Stream.fromIterable([todo]), - initialModel: todo, - ); + : super(stream: Stream.fromIterable([todo]), initialModel: todo); } test.Matcher get isChecked => CheckedMatcher(true); @@ -159,13 +133,14 @@ class CheckedMatcher extends test.Matcher { if (!wasCheckbox) { return description.replace('The item was not a checkbox'); } else { - return description - .replace('Checkbox was ${!checked} rather than $checked'); + return description.replace( + 'Checkbox was ${!checked} rather than $checked', + ); } } @override - bool matches(item, Map matchState) { + bool matches(item, Map matchState) { if (item is Checkbox) { return item.value == checked; } else { diff --git a/mvi_flutter/test_driver/integration_test.dart b/mvi_flutter/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/mvi_flutter/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/mvi_flutter/test_driver/todo_app.dart b/mvi_flutter/test_driver/todo_app.dart deleted file mode 100644 index 12a7577d..00000000 --- a/mvi_flutter/test_driver/todo_app.dart +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter_driver/driver_extension.dart'; -import 'package:mvi_flutter_sample/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/mvi_flutter/test_driver/todo_app_test.dart b/mvi_flutter/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/mvi_flutter/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/mvi_flutter/web/favicon.png b/mvi_flutter/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/mvi_flutter/web/favicon.png differ diff --git a/mvi_flutter/web/icons/Icon-192.png b/mvi_flutter/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/mvi_flutter/web/icons/Icon-192.png differ diff --git a/mvi_flutter/web/icons/Icon-512.png b/mvi_flutter/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/mvi_flutter/web/icons/Icon-512.png differ diff --git a/mvi_flutter/web/icons/Icon-maskable-192.png b/mvi_flutter/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/mvi_flutter/web/icons/Icon-maskable-192.png differ diff --git a/mvi_flutter/web/icons/Icon-maskable-512.png b/mvi_flutter/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/mvi_flutter/web/icons/Icon-maskable-512.png differ diff --git a/mvi_flutter/web/index.html b/mvi_flutter/web/index.html index 5dad3de1..8b82f0e1 100644 --- a/mvi_flutter/web/index.html +++ b/mvi_flutter/web/index.html @@ -1,10 +1,38 @@ + + + - mvi_flutter + + + + + + + + + + + + + mvi_flutter_sample + - + diff --git a/mvi_flutter/web/manifest.json b/mvi_flutter/web/manifest.json new file mode 100644 index 00000000..e3854a52 --- /dev/null +++ b/mvi_flutter/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "mvi_flutter_sample", + "short_name": "mvi_flutter_sample", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/mvi_flutter/windows/.gitignore b/mvi_flutter/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/mvi_flutter/windows/.gitignore @@ -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/ diff --git a/mvi_flutter/windows/CMakeLists.txt b/mvi_flutter/windows/CMakeLists.txt new file mode 100644 index 00000000..c338cda6 --- /dev/null +++ b/mvi_flutter/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(mvi_flutter_sample 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 "mvi_flutter_sample") + +# 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) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_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 "$") +# 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) diff --git a/mvi_flutter/windows/flutter/CMakeLists.txt b/mvi_flutter/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/mvi_flutter/windows/flutter/CMakeLists.txt @@ -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} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/mvi_flutter/windows/flutter/generated_plugin_registrant.cc b/mvi_flutter/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/mvi_flutter/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/mvi_flutter/windows/flutter/generated_plugin_registrant.h b/mvi_flutter/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/mvi_flutter/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/mvi_flutter/windows/flutter/generated_plugins.cmake b/mvi_flutter/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/mvi_flutter/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +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 $) + 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) diff --git a/mvi_flutter/windows/runner/CMakeLists.txt b/mvi_flutter/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/mvi_flutter/windows/runner/CMakeLists.txt @@ -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) diff --git a/mvi_flutter/windows/runner/Runner.rc b/mvi_flutter/windows/runner/Runner.rc new file mode 100644 index 00000000..87076f0d --- /dev/null +++ b/mvi_flutter/windows/runner/Runner.rc @@ -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", "com.example" "\0" + VALUE "FileDescription", "mvi_flutter_sample" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "mvi_flutter_sample" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "mvi_flutter_sample.exe" "\0" + VALUE "ProductName", "mvi_flutter_sample" "\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 diff --git a/mvi_flutter/windows/runner/flutter_window.cpp b/mvi_flutter/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/mvi_flutter/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#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( + 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 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); +} diff --git a/mvi_flutter/windows/runner/flutter_window.h b/mvi_flutter/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/mvi_flutter/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#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_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/mvi_flutter/windows/runner/main.cpp b/mvi_flutter/windows/runner/main.cpp new file mode 100644 index 00000000..f1f08a76 --- /dev/null +++ b/mvi_flutter/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 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"mvi_flutter_sample", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/mvi_flutter/windows/runner/resource.h b/mvi_flutter/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/mvi_flutter/windows/runner/resource.h @@ -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 diff --git a/mvi_flutter/windows/runner/resources/app_icon.ico b/mvi_flutter/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/mvi_flutter/windows/runner/resources/app_icon.ico differ diff --git a/mvi_flutter/windows/runner/runner.exe.manifest b/mvi_flutter/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/mvi_flutter/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/mvi_flutter/windows/runner/utils.cpp b/mvi_flutter/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/mvi_flutter/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +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 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::vector 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; +} diff --git a/mvi_flutter/windows/runner/utils.h b/mvi_flutter/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/mvi_flutter/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// 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, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/mvi_flutter/windows/runner/win32_window.cpp b/mvi_flutter/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/mvi_flutter/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#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(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( + 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(origin.x), + static_cast(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(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(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(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( + 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)); + } +} diff --git a/mvi_flutter/windows/runner/win32_window.h b/mvi_flutter/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/mvi_flutter/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// 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_ diff --git a/mvu/.flutter-plugins-dependencies b/mvu/.flutter-plugins-dependencies deleted file mode 100644 index 30693179..00000000 --- a/mvu/.flutter-plugins-dependencies +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"android":[{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":[]}],"date_created":"2020-02-10 11:24:26.886816","version":"1.14.7-pre.38"} \ No newline at end of file diff --git a/mvu/.gitignore b/mvu/.gitignore deleted file mode 100644 index 2ddde2a5..00000000 --- a/mvu/.gitignore +++ /dev/null @@ -1,73 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# 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 -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.packages -.pub-cache/ -.pub/ -/build/ - -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/mvu/.metadata b/mvu/.metadata deleted file mode 100644 index 1b5cec02..00000000 --- a/mvu/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 27321ebbad34b0a3fafe99fac037102196d655ff - channel: stable - -project_type: app diff --git a/mvu/README.md b/mvu/README.md deleted file mode 100644 index d935158e..00000000 --- a/mvu/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# MVU (Model-View-Update) - -This sample makes use of the [dartea](https://pub.dartlang.org/packages/dartea) and [built_value](https://pub.dartlang.org/packages/built_value) libraries to manage state. - - -[dartea](https://pub.dartlang.org/packages/dartea) is implementation of enginge for MVU pattern inspired by [TEA (The Elm Architecture)](https://guide.elm-lang.org/architecture/) and [Elmish (F# TEA implemetation)](https://fable-elmish.github.io/elmish/) - -![Simple MVU app](mvu_todo.png "Simple MVU app") - -## Components -* #### Model - This is a snapshot of your application's state, defined as an immutable data structure using the [built_value](https://pub.dartlang.org/packages/built_value) library. -* #### Update - This is a pure function that produces a new state of your application given the previous state and, optionally, new commands to process. - ```dart - Upd update(TMsg msg, TModel model) - ``` - `Upd` is simple data-container, it contains properties `model → TModel` and `effects → Cmd` (side-effects) -* #### View - This is a pure function that produces a new UI (Widget's tree) given the current state. - ```dart - Widget view(BuildContext ctx, Dispatch dispatch, TModel model) - ``` - Dispatch is simple function `void dispatch(TMsg msg)` which is dispatched `messages` into program loop. -* #### Message - This an event representing a change (delta) in the state of your application, originally defined as [Union type in Elm](https://guide.elm-lang.org/types/union_types.html) or [Discriminated union in F#](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions). Dart doesn't have built-in support for [Algebraic data types](https://en.wikipedia.org/wiki/Algebraic_data_type), so we can use simple inheritance instead. -* #### Command - This is a carrier of instructions, that when evaluated may produce one or more messages. It's used for controlled side-effects. -* #### Subscriptions - The events from the outside world, which are translated into messages. For example data from Websockets, timers and etc. - -## Key concepts -The heart of the MVU application are three yellow boxes on the diagram. First, the state of the app (Model) is mapped to the widgets tree (View). Second, events from the UI are translated into Messages and goes to the Update function (together with current app state). Update function is the brain of the app. It contains all the presentation logic, and it MUST be [pure](https://en.wikipedia.org/wiki/Pure_function). All the side-effects (such as database queries, http requests and etc) must be isolated using Commands and Subscriptions. - -### Code structure conventions -Every screen or component consists of `Model` and two main functions `update` and `view`. Optionally it may have `init` function, which creates initial state of a `Model`, and `subscription` function, which is subscribed to the events from the outside world and translates them to the `messages`. -For every screen we have thise files: -* ##### `state.dart` - `update`, `init` and `subscribe` functions. -* ##### `types.dart` and `types.g.dart` (generated with `built_value`) - `model`, `messages` and all the other classes which is required by `model`. -* ##### `view.dart` - `view` function. -* ##### `xxx.dart` - where `xxx` is screen or component name. It's composition (library) of all three parts above. - - -## Build -To enforcing `Model` immutability it need to be created with `built_value`. `built_value` library uses code generation. `built_value_generator` and `build_runner` are added as dev dependencies. -Whenever you update your Value Classes you need to run this command in console: -``` -flutter packages pub run build_runner build -``` -or run it in `watch` mode: -``` -flutter packages pub run build_runner watch -``` \ No newline at end of file diff --git a/mvu/android/.gitignore b/mvu/android/.gitignore deleted file mode 100644 index bc2100d8..00000000 --- a/mvu/android/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java diff --git a/mvu/android/app/build.gradle b/mvu/android/app/build.gradle deleted file mode 100644 index b109d5c8..00000000 --- a/mvu/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.mvu" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/mvu/android/app/src/debug/AndroidManifest.xml b/mvu/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 7d73ad0a..00000000 --- a/mvu/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/mvu/android/app/src/main/AndroidManifest.xml b/mvu/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index f52686b9..00000000 --- a/mvu/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - diff --git a/mvu/android/app/src/main/kotlin/com/example/mvu/MainActivity.kt b/mvu/android/app/src/main/kotlin/com/example/mvu/MainActivity.kt deleted file mode 100644 index e4e5b156..00000000 --- a/mvu/android/app/src/main/kotlin/com/example/mvu/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.mvu - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/mvu/android/app/src/main/res/drawable/launch_background.xml b/mvu/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/mvu/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/mvu/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/mvu/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index a3f285f9..00000000 Binary files a/mvu/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/mvu/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/mvu/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 5e6f3ac6..00000000 Binary files a/mvu/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/mvu/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/mvu/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 144d60be..00000000 Binary files a/mvu/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/mvu/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/mvu/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index deafae2d..00000000 Binary files a/mvu/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/mvu/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/mvu/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index d5614ac8..00000000 Binary files a/mvu/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/mvu/android/app/src/main/res/values/styles.xml b/mvu/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 00fa4417..00000000 --- a/mvu/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/mvu/android/app/src/profile/AndroidManifest.xml b/mvu/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 7d73ad0a..00000000 --- a/mvu/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/mvu/android/build.gradle b/mvu/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/mvu/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/mvu/android/gradle.properties b/mvu/android/gradle.properties deleted file mode 100644 index 38c8d454..00000000 --- a/mvu/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true -android.useAndroidX=true -android.enableJetifier=true diff --git a/mvu/android/gradle/wrapper/gradle-wrapper.properties b/mvu/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 296b146b..00000000 --- a/mvu/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/mvu/android/settings.gradle b/mvu/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/mvu/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/mvu/ios/.gitignore b/mvu/ios/.gitignore deleted file mode 100644 index e96ef602..00000000 --- a/mvu/ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/mvu/ios/Flutter/AppFrameworkInfo.plist b/mvu/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6b4c0f78..00000000 --- a/mvu/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/mvu/ios/Flutter/Debug.xcconfig b/mvu/ios/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba11..00000000 --- a/mvu/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/mvu/ios/Flutter/Release.xcconfig b/mvu/ios/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340..00000000 --- a/mvu/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/mvu/ios/Podfile b/mvu/ios/Podfile deleted file mode 100644 index b30a428b..00000000 --- a/mvu/ios/Podfile +++ /dev/null @@ -1,90 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '9.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; - end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end - end - generated_key_values -end - -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; - - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' - - # Plugin Pods - - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') - end -end - -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - -post_install do |installer| - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end - end -end diff --git a/mvu/ios/Runner.xcodeproj/project.pbxproj b/mvu/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 57e30aec..00000000 --- a/mvu/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,518 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.mvu; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.mvu; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.mvu; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/mvu/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mvu/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/mvu/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/mvu/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/mvu/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140cf..00000000 --- a/mvu/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mvu/ios/Runner.xcworkspace/contents.xcworkspacedata b/mvu/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/mvu/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/mvu/ios/Runner/AppDelegate.swift b/mvu/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a..00000000 --- a/mvu/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d22f10b2..00000000 --- a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 980e5ad6..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index fd870289..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 75e84cd1..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 03ab8a84..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index a03431cb..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index f47613ee..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 7f2230a9..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 42315c6d..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index f9882cc0..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 45537513..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 6360ea17..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 152d5e12..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 310b0b8f..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 092b7bfe..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2f..00000000 --- a/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/mvu/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -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. \ No newline at end of file diff --git a/mvu/ios/Runner/Base.lproj/LaunchScreen.storyboard b/mvu/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/mvu/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mvu/ios/Runner/Base.lproj/Main.storyboard b/mvu/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/mvu/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mvu/ios/Runner/Info.plist b/mvu/ios/Runner/Info.plist deleted file mode 100644 index f49048bd..00000000 --- a/mvu/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - mvu - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/mvu/ios/Runner/Runner-Bridging-Header.h b/mvu/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 7335fdf9..00000000 --- a/mvu/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file diff --git a/mvu/lib/common/extra_actions_menu.dart b/mvu/lib/common/extra_actions_menu.dart deleted file mode 100644 index 2b0cef7f..00000000 --- a/mvu/lib/common/extra_actions_menu.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -enum ExtraAction { toggleAll, clearCompleted } - -Widget buildExtraActionsMenu( - void Function(ExtraAction action) onSelected, bool allComplete) { - return PopupMenuButton( - key: ArchSampleKeys.extraActionsButton, - onSelected: onSelected, - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - key: ArchSampleKeys.toggleAll, - value: ExtraAction.toggleAll, - child: Text(allComplete - ? ArchSampleLocalizations.of(context).markAllIncomplete - : ArchSampleLocalizations.of(context).markAllComplete), - ), - PopupMenuItem( - key: ArchSampleKeys.clearCompleted, - value: ExtraAction.clearCompleted, - child: Text(ArchSampleLocalizations.of(context).clearCompleted), - ), - ], - ); -} diff --git a/mvu/lib/common/repository_commands.dart b/mvu/lib/common/repository_commands.dart deleted file mode 100644 index 1c2a6e79..00000000 --- a/mvu/lib/common/repository_commands.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'dart:async'; - -import 'package:dartea/dartea.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -abstract class RepositoryEvent {} - -class RepoOnTodoAdded implements RepositoryEvent { - final TodoEntity entity; - - RepoOnTodoAdded(this.entity); -} - -class RepoOnTodoRemoved implements RepositoryEvent { - final TodoEntity entity; - - RepoOnTodoRemoved(this.entity); -} - -class RepoOnTodoChanged implements RepositoryEvent { - final TodoEntity entity; - - RepoOnTodoChanged(this.entity); -} - -abstract class CmdRepository { - Cmd loadTodosCmd(T Function(List items) onSuccess, - {T Function(Exception exc) onError}); - - Cmd saveAllCmd(List entities, {T Function() onSuccess}); - - Cmd removeCmd(TodoEntity todo, {T Function() onSuccess}); - - Cmd saveCmd(TodoEntity todo, {T Function() onSuccess}); - - Cmd createCmd( - T Function(TodoEntity todo) onSuccess, String task, String note); - - Cmd updateDetailsCmd(T Function(TodoEntity todo) onSuccess, String id, - String task, String note); - - Stream get events; -} - -class TodosCmdRepository implements CmdRepository { - final TodosRepository _repo; - - TodosCmdRepository(this._repo); - - final StreamController _changesStreamController = - StreamController.broadcast(); - - @override - Stream get events => _changesStreamController.stream; - - @override - Cmd loadTodosCmd(T Function(List items) onSuccess, - {T Function(Exception exc) onError}) => - Cmd.ofAsyncFunc(_repo.loadTodos, onSuccess: onSuccess, onError: onError); - - @override - Cmd saveAllCmd(List entities, {T Function() onSuccess}) => - Cmd.ofAsyncAction(() => _repo.saveTodos(entities), - onSuccess: onSuccess); - - @override - Cmd removeCmd(TodoEntity todo, {T Function() onSuccess}) => - Cmd.ofAsyncAction(() async { - var todos = await _repo.loadTodos(); - await _repo.saveTodos(todos.where((x) => x.id != todo.id).toList()); - _changesStreamController.add(RepoOnTodoRemoved(todo)); - }, onSuccess: onSuccess); - - @override - Cmd saveCmd(TodoEntity todo, {T Function() onSuccess}) => - Cmd.ofAsyncAction(() async { - var todos = await _repo.loadTodos(); - await _repo - .saveTodos(todos.map((x) => x.id == todo.id ? todo : x).toList()); - _changesStreamController.add(RepoOnTodoChanged(todo)); - }, onSuccess: onSuccess); - - @override - Cmd createCmd( - T Function(TodoEntity todo) onSuccess, String task, String note) => - Cmd.ofAsyncFunc(() async { - var todo = TodoEntity(task, Uuid().generateV4(), note, false); - var todos = await _repo.loadTodos() - ..add(todo); - await _repo.saveTodos(todos); - _changesStreamController.add(RepoOnTodoAdded(todo)); - return todo; - }, onSuccess: onSuccess); - - @override - Cmd updateDetailsCmd(T Function(TodoEntity todo) onSuccess, String id, - String task, String note) => - Cmd.ofAsyncFunc(() async { - var todos = await _repo.loadTodos(); - var updated = todos - .map((x) => x.id == id ? TodoEntity(task, id, note, x.complete) : x) - .toList(); - await _repo.saveTodos(updated); - var updatedTodo = updated.firstWhere((x) => x.id == id); - _changesStreamController.add(RepoOnTodoChanged(updatedTodo)); - return updatedTodo; - }, onSuccess: onSuccess); -} - -const _internalRepository = LocalStorageRepository( - localStorage: FileStorage( - 'mvu_app', - getApplicationDocumentsDirectory, - ), - webClient: WebClient(), -); - -final CmdRepository repoCmds = TodosCmdRepository(_internalRepository); diff --git a/mvu/lib/common/router.dart b/mvu/lib/common/router.dart deleted file mode 100644 index 5c2e1434..00000000 --- a/mvu/lib/common/router.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:dartea/dartea.dart'; -import 'package:mvu/common/todo_model.dart'; -import 'package:mvu/details/details.dart' as details; -import 'package:mvu/edit/edit.dart' as edit; -import 'package:mvu/common/repository_commands.dart'; - -NavigatorState _navigator; - -void init(BuildContext context) { - _navigator = Navigator.of(context); -} - -Cmd goToDetailsScreen(TodoModel todo) => - Cmd.ofAction(() => _navigator.push(MaterialPageRoute( - builder: (_) => details.createProgram(repoCmds, todo).build()))); - -Cmd goToEditTodoScreen(TodoModel todo) => - Cmd.ofAction(() => _navigator.push(MaterialPageRoute( - builder: (_) => - edit.createProgram(repoCmds, todo: todo.toEntity()).build()))); - -Cmd goToCreateNewScreen() => Cmd.ofAction(() => _navigator.push( - MaterialPageRoute(builder: (_) => edit.createProgram(repoCmds).build()))); - -Cmd goBack() => Cmd.ofAction(() => _navigator.pop()); diff --git a/mvu/lib/common/snackbar.dart b/mvu/lib/common/snackbar.dart deleted file mode 100644 index 9caf4363..00000000 --- a/mvu/lib/common/snackbar.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:dartea/dartea.dart'; -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -ScaffoldState _scaffoldState; - -void init(BuildContext context) { - _scaffoldState = Scaffold.of(context); -} - -Cmd showUndoCmd(String task, TMsg Function() onUndo) { - return Cmd.ofEffect((Dispatch dispatch) { - _scaffoldState.showSnackBar( - SnackBar( - key: ArchSampleKeys.snackbar, - duration: Duration(seconds: 2), - content: Text( - ArchSampleLocalizations.of(_scaffoldState.context).todoDeleted(task), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - action: SnackBarAction( - label: ArchSampleLocalizations.of(_scaffoldState.context).undo, - onPressed: () => dispatch(onUndo()), - ), - ), - ); - }); -} diff --git a/mvu/lib/common/todo_model.dart b/mvu/lib/common/todo_model.dart deleted file mode 100644 index 81ad3892..00000000 --- a/mvu/lib/common/todo_model.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:built_value/built_value.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -part 'todo_model.g.dart'; - -abstract class TodoModel implements Built { - String get id; - bool get complete; - String get note; - String get task; - - TodoModel._(); - factory TodoModel([void Function(TodoModelBuilder b) updates]) = _$TodoModel; - - TodoEntity toEntity() { - return TodoEntity(task, id, note, complete); - } - - static TodoModel fromEntity(TodoEntity entity) { - var model = TodoModel((b) => b - ..task = entity.task - ..complete = entity.complete - ..note = entity.note - ..id = entity.id ?? Uuid().generateV4()); - return model; - } -} diff --git a/mvu/lib/common/todo_model.g.dart b/mvu/lib/common/todo_model.g.dart deleted file mode 100644 index de62d78e..00000000 --- a/mvu/lib/common/todo_model.g.dart +++ /dev/null @@ -1,137 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'todo_model.dart'; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -// ignore_for_file: always_put_control_body_on_new_line -// ignore_for_file: annotate_overrides -// ignore_for_file: avoid_annotating_with_dynamic -// ignore_for_file: avoid_catches_without_on_clauses -// ignore_for_file: avoid_returning_this -// ignore_for_file: lines_longer_than_80_chars -// ignore_for_file: omit_local_variable_types -// ignore_for_file: prefer_expression_function_bodies -// ignore_for_file: sort_constructors_first -// ignore_for_file: unnecessary_const -// ignore_for_file: unnecessary_new -// ignore_for_file: test_types_in_equals - -class _$TodoModel extends TodoModel { - @override - final String id; - @override - final bool complete; - @override - final String note; - @override - final String task; - - factory _$TodoModel([void Function(TodoModelBuilder b) updates]) => - (new TodoModelBuilder()..update(updates)).build(); - - _$TodoModel._({this.id, this.complete, this.note, this.task}) : super._() { - if (id == null) { - throw new BuiltValueNullFieldError('TodoModel', 'id'); - } - if (complete == null) { - throw new BuiltValueNullFieldError('TodoModel', 'complete'); - } - if (note == null) { - throw new BuiltValueNullFieldError('TodoModel', 'note'); - } - if (task == null) { - throw new BuiltValueNullFieldError('TodoModel', 'task'); - } - } - - @override - TodoModel rebuild(void Function(TodoModelBuilder b) updates) => - (toBuilder()..update(updates)).build(); - - @override - TodoModelBuilder toBuilder() => new TodoModelBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - return other is TodoModel && - id == other.id && - complete == other.complete && - note == other.note && - task == other.task; - } - - @override - int get hashCode { - return $jf($jc( - $jc($jc($jc(0, id.hashCode), complete.hashCode), note.hashCode), - task.hashCode)); - } - - @override - String toString() { - return (newBuiltValueToStringHelper('TodoModel') - ..add('id', id) - ..add('complete', complete) - ..add('note', note) - ..add('task', task)) - .toString(); - } -} - -class TodoModelBuilder implements Builder { - _$TodoModel _$v; - - String _id; - String get id => _$this._id; - set id(String id) => _$this._id = id; - - bool _complete; - bool get complete => _$this._complete; - set complete(bool complete) => _$this._complete = complete; - - String _note; - String get note => _$this._note; - set note(String note) => _$this._note = note; - - String _task; - String get task => _$this._task; - set task(String task) => _$this._task = task; - - TodoModelBuilder(); - - TodoModelBuilder get _$this { - if (_$v != null) { - _id = _$v.id; - _complete = _$v.complete; - _note = _$v.note; - _task = _$v.task; - _$v = null; - } - return this; - } - - @override - void replace(TodoModel other) { - if (other == null) { - throw new ArgumentError.notNull('other'); - } - _$v = other as _$TodoModel; - } - - @override - void update(void Function(TodoModelBuilder b) updates) { - if (updates != null) updates(this); - } - - @override - _$TodoModel build() { - final _$result = _$v ?? - new _$TodoModel._(id: id, complete: complete, note: note, task: task); - replace(_$result); - return _$result; - } -} diff --git a/mvu/lib/details/details.dart b/mvu/lib/details/details.dart deleted file mode 100644 index 06774a10..00000000 --- a/mvu/lib/details/details.dart +++ /dev/null @@ -1,39 +0,0 @@ -library details; - -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:dartea/dartea.dart'; -import 'package:mvu/details/types.dart'; -import 'package:mvu/common/todo_model.dart'; -import 'package:mvu/common/repository_commands.dart'; -import 'package:mvu/common/router.dart' as router; - -part 'state.dart'; -part 'view.dart'; - -Program> - createProgram(CmdRepository repo, TodoModel todo) => Program( - () => init(todo), (msg, model) => update(repo, msg, model), view, - subscription: (s, d, m) => _repoSubscription(repo, s, d, m)); - -StreamSubscription _repoSubscription( - CmdRepository repo, - StreamSubscription currentSub, - Dispatch dispatch, - DetailsModel model) { - if (currentSub != null) { - return currentSub; - } - final sub = repo.events.listen((event) { - if (event is RepoOnTodoChanged) { - dispatch(OnTodoChanged(event.entity)); - } - if (event is RepoOnTodoRemoved) { - dispatch(OnTodoRemoved(event.entity)); - } - }); - return sub; -} diff --git a/mvu/lib/details/state.dart b/mvu/lib/details/state.dart deleted file mode 100644 index f2a080ef..00000000 --- a/mvu/lib/details/state.dart +++ /dev/null @@ -1,40 +0,0 @@ -part of details; - -Upd init(TodoModel todo) { - var model = DetailsModel((b) => b..todo = todo.toBuilder()); - return Upd(model); -} - -Upd update( - CmdRepository repo, DetailsMessage msg, DetailsModel model) { - if (msg is Remove) { - var removeCmd = repo.removeCmd(model.todo.toEntity()); - return Upd(model, effects: removeCmd); - } - if (msg is ToggleCompleted) { - var updatedModel = - model.rebuild((b) => b.todo.update((t) => t.complete = !t.complete)); - return Upd(updatedModel, - effects: repo.saveCmd(updatedModel.todo.toEntity())); - } - if (msg is Edit) { - var navigateCmd = router.goToEditTodoScreen(model.todo); - return Upd(model, effects: navigateCmd); - } - if (msg is OnTodoChanged && - msg.entity != null && - msg.entity.id == model.todo.id) { - var updatedModel = model.rebuild((b) => b.todo - ..complete = msg.entity.complete - ..note = msg.entity.note - ..task = msg.entity.task); - return Upd(updatedModel); - } - if (msg is OnTodoRemoved && - msg.entity != null && - msg.entity.id == model.todo.id) { - var navigateCmd = router.goBack(); - return Upd(model, effects: navigateCmd); - } - return Upd(model); -} diff --git a/mvu/lib/details/types.dart b/mvu/lib/details/types.dart deleted file mode 100644 index b8ac0e53..00000000 --- a/mvu/lib/details/types.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:built_value/built_value.dart'; - -import 'package:todos_repository_core/todos_repository_core.dart'; -import 'package:mvu/common/todo_model.dart'; - -part 'types.g.dart'; - -abstract class DetailsModel - implements Built { - TodoModel get todo; - - DetailsModel._(); - factory DetailsModel([void Function(DetailsModelBuilder b) updates]) = - _$DetailsModel; -} - -abstract class DetailsMessage {} - -class Remove implements DetailsMessage {} - -class ToggleCompleted implements DetailsMessage {} - -class Edit implements DetailsMessage {} - -class OnTodoChanged implements DetailsMessage { - final TodoEntity entity; - OnTodoChanged(this.entity); -} - -class OnTodoRemoved implements DetailsMessage { - final TodoEntity entity; - OnTodoRemoved(this.entity); -} diff --git a/mvu/lib/details/types.g.dart b/mvu/lib/details/types.g.dart deleted file mode 100644 index 05b6b54a..00000000 --- a/mvu/lib/details/types.g.dart +++ /dev/null @@ -1,110 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'types.dart'; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -// ignore_for_file: always_put_control_body_on_new_line -// ignore_for_file: annotate_overrides -// ignore_for_file: avoid_annotating_with_dynamic -// ignore_for_file: avoid_catches_without_on_clauses -// ignore_for_file: avoid_returning_this -// ignore_for_file: lines_longer_than_80_chars -// ignore_for_file: omit_local_variable_types -// ignore_for_file: prefer_expression_function_bodies -// ignore_for_file: sort_constructors_first -// ignore_for_file: unnecessary_const -// ignore_for_file: unnecessary_new -// ignore_for_file: test_types_in_equals - -class _$DetailsModel extends DetailsModel { - @override - final TodoModel todo; - - factory _$DetailsModel([void Function(DetailsModelBuilder b) updates]) => - (new DetailsModelBuilder()..update(updates)).build(); - - _$DetailsModel._({this.todo}) : super._() { - if (todo == null) { - throw new BuiltValueNullFieldError('DetailsModel', 'todo'); - } - } - - @override - DetailsModel rebuild(void Function(DetailsModelBuilder b) updates) => - (toBuilder()..update(updates)).build(); - - @override - DetailsModelBuilder toBuilder() => new DetailsModelBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - return other is DetailsModel && todo == other.todo; - } - - @override - int get hashCode { - return $jf($jc(0, todo.hashCode)); - } - - @override - String toString() { - return (newBuiltValueToStringHelper('DetailsModel')..add('todo', todo)) - .toString(); - } -} - -class DetailsModelBuilder - implements Builder { - _$DetailsModel _$v; - - TodoModelBuilder _todo; - TodoModelBuilder get todo => _$this._todo ??= new TodoModelBuilder(); - set todo(TodoModelBuilder todo) => _$this._todo = todo; - - DetailsModelBuilder(); - - DetailsModelBuilder get _$this { - if (_$v != null) { - _todo = _$v.todo?.toBuilder(); - _$v = null; - } - return this; - } - - @override - void replace(DetailsModel other) { - if (other == null) { - throw new ArgumentError.notNull('other'); - } - _$v = other as _$DetailsModel; - } - - @override - void update(void Function(DetailsModelBuilder b) updates) { - if (updates != null) updates(this); - } - - @override - _$DetailsModel build() { - _$DetailsModel _$result; - try { - _$result = _$v ?? new _$DetailsModel._(todo: todo.build()); - } catch (_) { - String _$failedField; - try { - _$failedField = 'todo'; - todo.build(); - } catch (e) { - throw new BuiltValueNestedFieldError( - 'DetailsModel', _$failedField, e.toString()); - } - rethrow; - } - replace(_$result); - return _$result; - } -} diff --git a/mvu/lib/details/view.dart b/mvu/lib/details/view.dart deleted file mode 100644 index 11c4bf9c..00000000 --- a/mvu/lib/details/view.dart +++ /dev/null @@ -1,70 +0,0 @@ -part of details; - -Widget view(BuildContext context, Dispatch dispatch, - DetailsModel model) { - final localizations = ArchSampleLocalizations.of(context); - - return Scaffold( - key: ArchSampleKeys.todoDetailsScreen, - appBar: AppBar( - title: Text(localizations.todoDetails), - actions: [ - IconButton( - tooltip: localizations.deleteTodo, - icon: Icon(Icons.delete), - key: ArchSampleKeys.deleteTodoButton, - onPressed: () => dispatch(Remove()), - ) - ], - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: ListView( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(right: 8.0), - child: Checkbox( - key: ArchSampleKeys.detailsTodoItemCheckbox, - value: model.todo.complete, - onChanged: (_) => dispatch(ToggleCompleted()), - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), - child: Text( - model.todo.task, - key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, - ), - ), - Text( - model.todo.note, - key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) - ], - ), - ), - ], - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - key: ArchSampleKeys.editTodoFab, - tooltip: localizations.editTodo, - child: Icon(Icons.edit), - onPressed: () => dispatch(Edit()), - ), - ); -} diff --git a/mvu/lib/edit/edit.dart b/mvu/lib/edit/edit.dart deleted file mode 100644 index 33f8cf2c..00000000 --- a/mvu/lib/edit/edit.dart +++ /dev/null @@ -1,18 +0,0 @@ -library edit; - -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; -import 'package:dartea/dartea.dart'; -import 'package:mvu/edit/types.dart'; -import 'package:mvu/common/repository_commands.dart' show CmdRepository; -import 'package:mvu/common/router.dart' as router; - -part 'state.dart'; -part 'view.dart'; - -Program createProgram( - CmdRepository repo, - {TodoEntity todo}) => - Program(() => init(todo), (msg, model) => update(repo, msg, model), view); diff --git a/mvu/lib/edit/state.dart b/mvu/lib/edit/state.dart deleted file mode 100644 index 1ecc52a4..00000000 --- a/mvu/lib/edit/state.dart +++ /dev/null @@ -1,25 +0,0 @@ -part of edit; - -Upd init(TodoEntity todo) { - var model = EditTodoModel((b) => b - ..id = todo != null ? todo.id : '' - ..note = TextEditingController(text: todo != null ? todo.note : '') - ..task = TextEditingController(text: todo != null ? todo.task : '')); - return Upd(model); -} - -Upd update( - CmdRepository repo, EditTodoMessage msg, EditTodoModel model) { - if (msg is Save && model.task.text.isNotEmpty) { - var updateCmd = model.id.isEmpty - ? repo.createCmd((t) => OnSaved(t), model.task.text, model.note.text) - : repo.updateDetailsCmd( - (t) => OnSaved(t), model.id, model.task.text, model.note.text); - return Upd(model, effects: updateCmd); - } - if (msg is OnSaved && msg.todo != null) { - var navCmd = router.goBack(); - return Upd(model, effects: navCmd); - } - return Upd(model); -} diff --git a/mvu/lib/edit/types.dart b/mvu/lib/edit/types.dart deleted file mode 100644 index ff8ee109..00000000 --- a/mvu/lib/edit/types.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:built_value/built_value.dart'; -import 'package:flutter/widgets.dart' as widgets; -import 'package:todos_repository_core/todos_repository_core.dart'; - -part 'types.g.dart'; - -abstract class EditTodoModel - implements Built { - widgets.TextEditingController get task; - - widgets.TextEditingController get note; - - String get id; - - EditTodoModel._(); - - factory EditTodoModel([void Function(EditTodoModelBuilder b) update]) = - _$EditTodoModel; -} - -abstract class EditTodoMessage {} - -class Save implements EditTodoMessage {} - -class OnSaved implements EditTodoMessage { - final TodoEntity todo; - - OnSaved(this.todo); -} diff --git a/mvu/lib/edit/types.g.dart b/mvu/lib/edit/types.g.dart deleted file mode 100644 index 311ee29e..00000000 --- a/mvu/lib/edit/types.g.dart +++ /dev/null @@ -1,124 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'types.dart'; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -// ignore_for_file: always_put_control_body_on_new_line -// ignore_for_file: annotate_overrides -// ignore_for_file: avoid_annotating_with_dynamic -// ignore_for_file: avoid_catches_without_on_clauses -// ignore_for_file: avoid_returning_this -// ignore_for_file: lines_longer_than_80_chars -// ignore_for_file: omit_local_variable_types -// ignore_for_file: prefer_expression_function_bodies -// ignore_for_file: sort_constructors_first -// ignore_for_file: unnecessary_const -// ignore_for_file: unnecessary_new -// ignore_for_file: test_types_in_equals - -class _$EditTodoModel extends EditTodoModel { - @override - final widgets.TextEditingController task; - @override - final widgets.TextEditingController note; - @override - final String id; - - factory _$EditTodoModel([void Function(EditTodoModelBuilder b) updates]) => - (new EditTodoModelBuilder()..update(updates)).build(); - - _$EditTodoModel._({this.task, this.note, this.id}) : super._() { - if (task == null) { - throw new BuiltValueNullFieldError('EditTodoModel', 'task'); - } - if (note == null) { - throw new BuiltValueNullFieldError('EditTodoModel', 'note'); - } - if (id == null) { - throw new BuiltValueNullFieldError('EditTodoModel', 'id'); - } - } - - @override - EditTodoModel rebuild(void Function(EditTodoModelBuilder b) updates) => - (toBuilder()..update(updates)).build(); - - @override - EditTodoModelBuilder toBuilder() => new EditTodoModelBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - return other is EditTodoModel && - task == other.task && - note == other.note && - id == other.id; - } - - @override - int get hashCode { - return $jf($jc($jc($jc(0, task.hashCode), note.hashCode), id.hashCode)); - } - - @override - String toString() { - return (newBuiltValueToStringHelper('EditTodoModel') - ..add('task', task) - ..add('note', note) - ..add('id', id)) - .toString(); - } -} - -class EditTodoModelBuilder - implements Builder { - _$EditTodoModel _$v; - - widgets.TextEditingController _task; - widgets.TextEditingController get task => _$this._task; - set task(widgets.TextEditingController task) => _$this._task = task; - - widgets.TextEditingController _note; - widgets.TextEditingController get note => _$this._note; - set note(widgets.TextEditingController note) => _$this._note = note; - - String _id; - String get id => _$this._id; - set id(String id) => _$this._id = id; - - EditTodoModelBuilder(); - - EditTodoModelBuilder get _$this { - if (_$v != null) { - _task = _$v.task; - _note = _$v.note; - _id = _$v.id; - _$v = null; - } - return this; - } - - @override - void replace(EditTodoModel other) { - if (other == null) { - throw new ArgumentError.notNull('other'); - } - _$v = other as _$EditTodoModel; - } - - @override - void update(void Function(EditTodoModelBuilder b) updates) { - if (updates != null) updates(this); - } - - @override - _$EditTodoModel build() { - final _$result = - _$v ?? new _$EditTodoModel._(task: task, note: note, id: id); - replace(_$result); - return _$result; - } -} diff --git a/mvu/lib/edit/view.dart b/mvu/lib/edit/view.dart deleted file mode 100644 index e8af30c4..00000000 --- a/mvu/lib/edit/view.dart +++ /dev/null @@ -1,54 +0,0 @@ -part of edit; - -Widget view(BuildContext context, Dispatch dispatch, - EditTodoModel model) { - final localizations = ArchSampleLocalizations.of(context); - final textTheme = Theme.of(context).textTheme; - final isEditing = model.id.isNotEmpty; - - return Scaffold( - key: ArchSampleKeys.editTodoScreen, - appBar: AppBar( - title: Text( - isEditing ? localizations.editTodo : localizations.addTodo, - ), - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: Form( - autovalidate: true, - child: ListView( - children: [ - TextFormField( - key: ArchSampleKeys.taskField, - controller: model.task, - autofocus: !isEditing, - style: textTheme.headline, - decoration: InputDecoration( - hintText: localizations.newTodoHint, - ), - validator: (val) { - return val.trim().isEmpty ? localizations.emptyTodoError : null; - }, - ), - TextFormField( - key: ArchSampleKeys.noteField, - controller: model.note, - maxLines: 10, - style: textTheme.subhead, - decoration: InputDecoration( - hintText: localizations.notesHint, - ), - ) - ], - ), - ), - ), - floatingActionButton: FloatingActionButton( - key: isEditing ? ArchSampleKeys.saveTodoFab : ArchSampleKeys.saveNewTodo, - tooltip: isEditing ? localizations.saveChanges : localizations.addTodo, - child: Icon(isEditing ? Icons.check : Icons.add), - onPressed: () => dispatch(Save()), - ), - ); -} diff --git a/mvu/lib/home/home.dart b/mvu/lib/home/home.dart deleted file mode 100644 index 410e9a15..00000000 --- a/mvu/lib/home/home.dart +++ /dev/null @@ -1,46 +0,0 @@ -library home; - -import 'dart:async'; - -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:dartea/dartea.dart'; -import 'package:mvu/localization.dart'; -import 'package:mvu/home/types.dart'; -import 'package:mvu/stats/types.dart'; -import 'package:mvu/todos/types.dart'; -import 'package:mvu/common/repository_commands.dart'; -import 'package:mvu/todos/todos.dart' as todos; -import 'package:mvu/stats/stats.dart' as stats; -import 'package:mvu/common/router.dart' as router; -import 'package:mvu/common/snackbar.dart' as snackbar; - -part 'state.dart'; -part 'view.dart'; - -Program> - createProgram(AppTab initTab) => Program(() => init(initTab), update, view, - subscription: _repoSubscription); - -StreamSubscription _repoSubscription( - StreamSubscription currentSub, - Dispatch dispatch, - HomeModel model) { - if (currentSub != null) { - return currentSub; - } - final sub = repoCmds.events.listen((event) { - if (event is RepoOnTodoAdded) { - dispatch(OnNewTodoCreated(event.entity)); - } - if (event is RepoOnTodoChanged) { - dispatch(TodosMsg(OnTodoItemChanged(updated: event.entity))); - } - if (event is RepoOnTodoRemoved) { - dispatch(TodosMsg(OnTodoItemChanged(removed: event.entity))); - } - }); - return sub; -} diff --git a/mvu/lib/home/state.dart b/mvu/lib/home/state.dart deleted file mode 100644 index 2cde1ac0..00000000 --- a/mvu/lib/home/state.dart +++ /dev/null @@ -1,65 +0,0 @@ -part of home; - -Upd init(AppTab currentTab) { - var body = _initBody(currentTab); - var model = HomeModel((b) => b..body = body.model); - return Upd(model, effects: body.effects); -} - -Upd update(HomeMessage msg, HomeModel model) { - if (msg is TabChangedMessage) { - if (msg.value == model.body.tag) { - return Upd(model); - } - - var body = _initBody(msg.value); - var updated = model.rebuild((b) => b..body = body.model); - return Upd(updated, effects: body.effects); - } - - if (msg is CreateNewTodo) { - var navCmd = router.goToCreateNewScreen(); - return Upd(model, effects: navCmd); - } - - if (msg is OnNewTodoCreated) { - if (model.body.tag == AppTab.todos) { - return Upd(model, - effects: Cmd.ofMsg(TodosMsg(OnTodoItemChanged(created: msg.entity)))); - } else if (model.body.tag == AppTab.stats) { - return Upd(model, - effects: Cmd.ofMsg(StatsMsg(OnNewTaskCreated(msg.entity)))); - } - } - - if (msg is TodosMsg && model.body.tag == AppTab.todos) { - var updatedTodos = todos.update(repoCmds, msg.message, model.body.model); - var updatedModel = - model.rebuild((b) => b..body = TodosBody(updatedTodos.model)); - var effects = Cmd.fmap((m) => TodosMsg(m), updatedTodos.effects); - return Upd(updatedModel, effects: effects); - } - - if (msg is StatsMsg && model.body.tag == AppTab.stats) { - var updatedStats = stats.update(repoCmds, msg.message, model.body.model); - var updatedModel = - model.rebuild((b) => b..body = StatsBody(updatedStats.model)); - return Upd(updatedModel, - effects: Cmd.fmap((m) => StatsMsg(m), updatedStats.effects)); - } - return Upd(model); -} - -Upd _initBody(AppTab tag) { - switch (tag) { - case AppTab.todos: - var initedTodos = todos.init(VisibilityFilter.all); - return Upd(TodosBody(initedTodos.model), - effects: Cmd.fmap((m) => TodosMsg(m), initedTodos.effects)); - case AppTab.stats: - var initedStats = stats.init(); - return Upd(StatsBody(initedStats.model), - effects: Cmd.fmap((m) => StatsMsg(m), initedStats.effects)); - } - throw ArgumentError.value(tag); -} diff --git a/mvu/lib/home/types.dart b/mvu/lib/home/types.dart deleted file mode 100644 index a32e9ed9..00000000 --- a/mvu/lib/home/types.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'package:built_value/built_value.dart'; - -import 'package:mvu/todos/types.dart'; -import 'package:mvu/stats/types.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -part 'types.g.dart'; - -enum AppTab { todos, stats } -enum VisibilityFilter { all, active, completed } - -abstract class HomeMessage {} - -class TabChangedMessage implements HomeMessage { - final AppTab value; - TabChangedMessage(this.value); -} - -class CreateNewTodo implements HomeMessage {} - -class OnNewTodoCreated implements HomeMessage { - final TodoEntity entity; - OnNewTodoCreated(this.entity); -} - -class TodosMsg implements HomeMessage { - final TodosMessage message; - TodosMsg(this.message); -} - -class StatsMsg implements HomeMessage { - final StatsMessage message; - StatsMsg(this.message); -} - -abstract class HomeModel implements Built { - BodyModel get body; - - HomeModel._(); - factory HomeModel([void Function(HomeModelBuilder b) updates]) = _$HomeModel; -} - -abstract class BodyModel { - AppTab get tag; - TModel get model; -} - -class TodosBody implements BodyModel { - final TodosModel _model; - - TodosBody(this._model); - - @override - AppTab get tag => AppTab.todos; - - @override - TodosModel get model => _model; -} - -class StatsBody implements BodyModel { - final StatsModel _model; - - StatsBody(this._model); - - @override - AppTab get tag => AppTab.stats; - - @override - StatsModel get model => _model; -} diff --git a/mvu/lib/home/types.g.dart b/mvu/lib/home/types.g.dart deleted file mode 100644 index feda38e6..00000000 --- a/mvu/lib/home/types.g.dart +++ /dev/null @@ -1,96 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'types.dart'; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -// ignore_for_file: always_put_control_body_on_new_line -// ignore_for_file: annotate_overrides -// ignore_for_file: avoid_annotating_with_dynamic -// ignore_for_file: avoid_catches_without_on_clauses -// ignore_for_file: avoid_returning_this -// ignore_for_file: lines_longer_than_80_chars -// ignore_for_file: omit_local_variable_types -// ignore_for_file: prefer_expression_function_bodies -// ignore_for_file: sort_constructors_first -// ignore_for_file: unnecessary_const -// ignore_for_file: unnecessary_new -// ignore_for_file: test_types_in_equals - -class _$HomeModel extends HomeModel { - @override - final BodyModel body; - - factory _$HomeModel([void Function(HomeModelBuilder b) updates]) => - (new HomeModelBuilder()..update(updates)).build(); - - _$HomeModel._({this.body}) : super._() { - if (body == null) { - throw new BuiltValueNullFieldError('HomeModel', 'body'); - } - } - - @override - HomeModel rebuild(void Function(HomeModelBuilder b) updates) => - (toBuilder()..update(updates)).build(); - - @override - HomeModelBuilder toBuilder() => new HomeModelBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - return other is HomeModel && body == other.body; - } - - @override - int get hashCode { - return $jf($jc(0, body.hashCode)); - } - - @override - String toString() { - return (newBuiltValueToStringHelper('HomeModel')..add('body', body)) - .toString(); - } -} - -class HomeModelBuilder implements Builder { - _$HomeModel _$v; - - BodyModel _body; - BodyModel get body => _$this._body; - set body(BodyModel body) => _$this._body = body; - - HomeModelBuilder(); - - HomeModelBuilder get _$this { - if (_$v != null) { - _body = _$v.body; - _$v = null; - } - return this; - } - - @override - void replace(HomeModel other) { - if (other == null) { - throw new ArgumentError.notNull('other'); - } - _$v = other as _$HomeModel; - } - - @override - void update(void Function(HomeModelBuilder b) updates) { - if (updates != null) updates(this); - } - - @override - _$HomeModel build() { - final _$result = _$v ?? new _$HomeModel._(body: body); - replace(_$result); - return _$result; - } -} diff --git a/mvu/lib/home/view.dart b/mvu/lib/home/view.dart deleted file mode 100644 index 71b748bc..00000000 --- a/mvu/lib/home/view.dart +++ /dev/null @@ -1,71 +0,0 @@ -part of home; - -Widget view( - BuildContext context, Dispatch dispatch, HomeModel model) { - return Scaffold( - key: ArchSampleKeys.homeScreen, - appBar: AppBar( - title: Text(MvuLocalizations().appTitle), - actions: _getAppBarActions(context, dispatch, model.body), - ), - body: Builder(builder: (ctx) => _body(ctx, dispatch, model.body)), - floatingActionButton: FloatingActionButton( - key: ArchSampleKeys.addTodoFab, - onPressed: () => dispatch(CreateNewTodo()), - child: Icon(Icons.add), - tooltip: ArchSampleLocalizations.of(context).addTodo, - ), - bottomNavigationBar: _bottomNavigation(context, dispatch, model.body.tag), - ); -} - -List _getAppBarActions( - BuildContext context, Dispatch dispatch, BodyModel body) { - if (body.tag == AppTab.todos) { - var extraActions = - todos.buildExtraActionsMenu((m) => dispatch(TodosMsg(m)), body.model); - var filterMenu = todos.buildFilterMenu( - context, (m) => dispatch(TodosMsg(m)), body.model); - return [filterMenu, extraActions]; - } - if (body.tag == AppTab.stats) { - var extraActions = - stats.buildExtraActionsMenu((m) => dispatch(StatsMsg(m)), body.model); - return [extraActions]; - } - return [Container()]; -} - -Widget _bottomNavigation( - BuildContext context, Dispatch dispatch, AppTab current) { - return BottomNavigationBar( - key: ArchSampleKeys.tabs, - currentIndex: AppTab.values.indexOf(current), - onTap: ((i) => dispatch(TabChangedMessage(AppTab.values[i]))), - items: AppTab.values.map((tab) { - return BottomNavigationBarItem( - icon: Icon( - tab == AppTab.todos ? Icons.list : Icons.show_chart, - key: tab == AppTab.todos - ? ArchSampleKeys.todoTab - : ArchSampleKeys.statsTab, - ), - title: Text(tab == AppTab.stats - ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos), - ); - }).toList(), - ); -} - -Widget _body( - BuildContext context, Dispatch dispatch, BodyModel body) { - snackbar.init(context); - switch (body.tag) { - case AppTab.todos: - return todos.view(context, (m) => dispatch(TodosMsg(m)), body.model); - case AppTab.stats: - return stats.view(context, (m) => dispatch(StatsMsg(m)), body.model); - } - return Text('Unknown tag: ${body.tag}'); -} diff --git a/mvu/lib/localization.dart b/mvu/lib/localization.dart deleted file mode 100644 index 6ab2920e..00000000 --- a/mvu/lib/localization.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; - -class MvuLocalizations { - static MvuLocalizations of(BuildContext context) { - return Localizations.of( - context, - MvuLocalizations, - ); - } - - String get appTitle => 'MVU Example'; -} - -class MvuLocalizationsDelegate extends LocalizationsDelegate { - @override - Future load(Locale locale) => - Future(() => MvuLocalizations()); - - @override - bool shouldReload(MvuLocalizationsDelegate old) => false; - - @override - bool isSupported(Locale locale) => - locale.languageCode.toLowerCase().contains('en'); -} diff --git a/mvu/lib/main.dart b/mvu/lib/main.dart deleted file mode 100644 index 8b924e5a..00000000 --- a/mvu/lib/main.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:todos_app_core/todos_app_core.dart'; - -import 'package:mvu/common/router.dart' as router; -import 'package:mvu/home/home.dart' as home; -import 'package:mvu/home/types.dart'; -import 'package:mvu/edit/edit.dart' as edit; -import 'localization.dart'; -import 'package:mvu/common/repository_commands.dart' show repoCmds; - -void main() { - runApp(MyApp()); -} - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - theme: ArchSampleTheme.theme, - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - MvuLocalizationsDelegate() - ], - home: Builder( - builder: (c) { - router.init(c); - return home.createProgram(AppTab.todos).build(); - }, - ), - routes: { - ArchSampleRoutes.addTodo: (_) => edit.createProgram(repoCmds).build() - }, - ); - } -} diff --git a/mvu/lib/stats/state.dart b/mvu/lib/stats/state.dart deleted file mode 100644 index 64bd992e..00000000 --- a/mvu/lib/stats/state.dart +++ /dev/null @@ -1,72 +0,0 @@ -part of stats; - -Upd init() { - var model = StatsModel((b) => b - ..items = BuiltList().toBuilder() - ..activeCount = 0 - ..completedCount = 0 - ..loading = false); - return Upd(model, effects: Cmd.ofMsg(LoadStats())); -} - -Upd update( - CmdRepository repo, StatsMessage msg, StatsModel model) { - if (msg is LoadStats) { - var updatedModel = model.rebuild((b) => b..loading = true); - var loadCmd = repo.loadTodosCmd((items) => OnStatsLoaded(items)); - return Upd(updatedModel, effects: loadCmd); - } - if (msg is OnStatsLoaded) { - var updatedModel = _onItemsChanged(model, msg.todos); - updatedModel = _calculateStats(updatedModel); - updatedModel = updatedModel.rebuild((b) => b..loading = false); - return Upd(updatedModel); - } - if (msg is ToggleAllMessage) { - return _toggleAll(repo, model, msg); - } - if (msg is CleareCompletedMessage) { - var updatedModel = model.rebuild((b) => b.items.where((t) => !t.complete)); - updatedModel = _calculateStats(updatedModel); - return Upd(updatedModel, effects: _saveItems(repo, updatedModel)); - } - if (msg is OnNewTaskCreated) { - var updatedModel = - model.rebuild((b) => b.items.add(TodoModel.fromEntity(msg.entity))); - updatedModel = _calculateStats(updatedModel); - return Upd(updatedModel); - } - return Upd(model); -} - -StatsModel _onItemsChanged(StatsModel model, List newItems) { - return model.rebuild((b) => b - ..items.clear() - ..items.addAll(newItems.map((x) => TodoModel.fromEntity(x)))); -} - -StatsModel _calculateStats(StatsModel model) { - var completedCount = - model.items.fold(0, (acc, t) => t.complete ? acc + 1 : acc); - var activeCount = model.items.length - completedCount; - var updatedModel = model.rebuild((b) => b - ..activeCount = activeCount - ..completedCount = completedCount); - return updatedModel; -} - -Upd _toggleAll( - CmdRepository repo, StatsModel model, ToggleAllMessage msg) { - var setComplete = model.items.any((x) => !x.complete); - var activeCount = setComplete ? 0 : model.items.length; - var completedCount = setComplete ? model.items.length : 0; - - var updatedModel = model.rebuild((b) => b - ..items.map((t) => t.rebuild((x) => x..complete = setComplete)) - ..activeCount = activeCount - ..completedCount = completedCount); - return Upd(updatedModel, effects: _saveItems(repo, updatedModel)); -} - -Cmd _saveItems(CmdRepository repo, StatsModel model) => - repo.saveAllCmd(model.items.map((x) => x.toEntity()).toList()); diff --git a/mvu/lib/stats/stats.dart b/mvu/lib/stats/stats.dart deleted file mode 100644 index 9d1a544e..00000000 --- a/mvu/lib/stats/stats.dart +++ /dev/null @@ -1,15 +0,0 @@ -library stats; - -import 'package:flutter/material.dart'; -import 'package:built_collection/built_collection.dart'; - -import 'package:todos_repository_core/todos_repository_core.dart'; -import 'package:mvu/common/repository_commands.dart' show CmdRepository; -import 'package:mvu/common/todo_model.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:dartea/dartea.dart'; -import 'package:mvu/stats/types.dart'; -import 'package:mvu/common/extra_actions_menu.dart' as menu; - -part 'state.dart'; -part 'view.dart'; diff --git a/mvu/lib/stats/types.dart b/mvu/lib/stats/types.dart deleted file mode 100644 index e2a75faa..00000000 --- a/mvu/lib/stats/types.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:built_collection/built_collection.dart'; -import 'package:built_value/built_value.dart'; - -import 'package:todos_repository_core/todos_repository_core.dart'; -import 'package:mvu/common/todo_model.dart'; - -part 'types.g.dart'; - -abstract class StatsMessage {} - -class LoadStats implements StatsMessage {} - -class OnStatsLoaded implements StatsMessage { - final List todos; - OnStatsLoaded(this.todos); -} - -class ToggleAllMessage implements StatsMessage {} - -class CleareCompletedMessage implements StatsMessage {} - -class OnNewTaskCreated implements StatsMessage { - final TodoEntity entity; - OnNewTaskCreated(this.entity); -} - -abstract class StatsModel implements Built { - BuiltList get items; - bool get loading; - int get activeCount; - int get completedCount; - - StatsModel._(); - factory StatsModel([void Function(StatsModelBuilder b) updates]) = - _$StatsModel; -} diff --git a/mvu/lib/stats/types.g.dart b/mvu/lib/stats/types.g.dart deleted file mode 100644 index 3c37ed48..00000000 --- a/mvu/lib/stats/types.g.dart +++ /dev/null @@ -1,159 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'types.dart'; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -// ignore_for_file: always_put_control_body_on_new_line -// ignore_for_file: annotate_overrides -// ignore_for_file: avoid_annotating_with_dynamic -// ignore_for_file: avoid_catches_without_on_clauses -// ignore_for_file: avoid_returning_this -// ignore_for_file: lines_longer_than_80_chars -// ignore_for_file: omit_local_variable_types -// ignore_for_file: prefer_expression_function_bodies -// ignore_for_file: sort_constructors_first -// ignore_for_file: unnecessary_const -// ignore_for_file: unnecessary_new -// ignore_for_file: test_types_in_equals - -class _$StatsModel extends StatsModel { - @override - final BuiltList items; - @override - final bool loading; - @override - final int activeCount; - @override - final int completedCount; - - factory _$StatsModel([void Function(StatsModelBuilder b) updates]) => - (new StatsModelBuilder()..update(updates)).build(); - - _$StatsModel._( - {this.items, this.loading, this.activeCount, this.completedCount}) - : super._() { - if (items == null) { - throw new BuiltValueNullFieldError('StatsModel', 'items'); - } - if (loading == null) { - throw new BuiltValueNullFieldError('StatsModel', 'loading'); - } - if (activeCount == null) { - throw new BuiltValueNullFieldError('StatsModel', 'activeCount'); - } - if (completedCount == null) { - throw new BuiltValueNullFieldError('StatsModel', 'completedCount'); - } - } - - @override - StatsModel rebuild(void Function(StatsModelBuilder b) updates) => - (toBuilder()..update(updates)).build(); - - @override - StatsModelBuilder toBuilder() => new StatsModelBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - return other is StatsModel && - items == other.items && - loading == other.loading && - activeCount == other.activeCount && - completedCount == other.completedCount; - } - - @override - int get hashCode { - return $jf($jc( - $jc($jc($jc(0, items.hashCode), loading.hashCode), - activeCount.hashCode), - completedCount.hashCode)); - } - - @override - String toString() { - return (newBuiltValueToStringHelper('StatsModel') - ..add('items', items) - ..add('loading', loading) - ..add('activeCount', activeCount) - ..add('completedCount', completedCount)) - .toString(); - } -} - -class StatsModelBuilder implements Builder { - _$StatsModel _$v; - - ListBuilder _items; - ListBuilder get items => - _$this._items ??= new ListBuilder(); - set items(ListBuilder items) => _$this._items = items; - - bool _loading; - bool get loading => _$this._loading; - set loading(bool loading) => _$this._loading = loading; - - int _activeCount; - int get activeCount => _$this._activeCount; - set activeCount(int activeCount) => _$this._activeCount = activeCount; - - int _completedCount; - int get completedCount => _$this._completedCount; - set completedCount(int completedCount) => - _$this._completedCount = completedCount; - - StatsModelBuilder(); - - StatsModelBuilder get _$this { - if (_$v != null) { - _items = _$v.items?.toBuilder(); - _loading = _$v.loading; - _activeCount = _$v.activeCount; - _completedCount = _$v.completedCount; - _$v = null; - } - return this; - } - - @override - void replace(StatsModel other) { - if (other == null) { - throw new ArgumentError.notNull('other'); - } - _$v = other as _$StatsModel; - } - - @override - void update(void Function(StatsModelBuilder b) updates) { - if (updates != null) updates(this); - } - - @override - _$StatsModel build() { - _$StatsModel _$result; - try { - _$result = _$v ?? - new _$StatsModel._( - items: items.build(), - loading: loading, - activeCount: activeCount, - completedCount: completedCount); - } catch (_) { - String _$failedField; - try { - _$failedField = 'items'; - items.build(); - } catch (e) { - throw new BuiltValueNestedFieldError( - 'StatsModel', _$failedField, e.toString()); - } - rethrow; - } - replace(_$result); - return _$result; - } -} diff --git a/mvu/lib/stats/view.dart b/mvu/lib/stats/view.dart deleted file mode 100644 index 09a40318..00000000 --- a/mvu/lib/stats/view.dart +++ /dev/null @@ -1,65 +0,0 @@ -part of stats; - -Widget buildExtraActionsMenu( - Dispatch dispatch, StatsModel model) { - var allComplete = !model.items.any((x) => !x.complete); - return menu.buildExtraActionsMenu( - (act) => dispatch(_toMessage(act)), allComplete); -} - -Widget view( - BuildContext context, Dispatch dispatch, StatsModel model) { - return model.loading - ? Center( - key: ArchSampleKeys.statsLoading, - child: CircularProgressIndicator( - key: ArchSampleKeys.statsLoading, - )) - : Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '${model.completedCount}', - key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '${model.activeCount}', - key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, - ), - ) - ], - ), - ); -} - -StatsMessage _toMessage(menu.ExtraAction action) { - switch (action) { - case menu.ExtraAction.toggleAll: - return ToggleAllMessage(); - case menu.ExtraAction.clearCompleted: - default: - return CleareCompletedMessage(); - } -} diff --git a/mvu/lib/todos/state.dart b/mvu/lib/todos/state.dart deleted file mode 100644 index 392fdde5..00000000 --- a/mvu/lib/todos/state.dart +++ /dev/null @@ -1,125 +0,0 @@ -part of todos; - -Upd init(VisibilityFilter filter) { - var model = TodosModel((b) => b - ..isLoading = false - ..filter = filter - ..items = BuiltList().toBuilder()); - return Upd(model, effects: Cmd.ofMsg(LoadTodos())); -} - -Upd update( - CmdRepository repo, TodosMessage msg, TodosModel model) { - if (msg is LoadTodos) { - return _loadTodos(repo, model); - } - if (msg is OnTodosLoaded) { - return _onTodosLoaded(model, msg); - } - if (msg is OnTodosLoadError) { - return _onLoadingError(model, msg); - } - if (msg is UpdateTodo) { - return _toggleTodo(repo, model, msg); - } - if (msg is RemoveTodo) { - var updatedModel = _removeTodo(model, msg.todo.id); - return Upd(updatedModel, effects: repo.removeCmd(msg.todo.toEntity())); - } - if (msg is UndoRemoveItem) { - var updatedModel = model.rebuild((b) => b.items.add(msg.item)); - return Upd(updatedModel, effects: _saveTodosCmd(repo, updatedModel)); - } - if (msg is FilterChanged) { - var updatedModel = model.rebuild((b) => b..filter = msg.value); - return Upd(updatedModel); - } - if (msg is ToggleAllMessage) { - return _toggleAll(repo, model, msg); - } - if (msg is CleareCompletedMessage) { - var updatedModel = model.rebuild((b) => b.items.where((t) => !t.complete)); - return Upd(updatedModel, effects: _saveTodosCmd(repo, updatedModel)); - } - if (msg is ShowDetailsMessage) { - var navigateCmd = router.goToDetailsScreen(msg.todo); - return Upd(model, effects: navigateCmd); - } - if (msg is OnTodoItemChanged) { - return _onRepoEvent(model, msg); - } - return Upd(model); -} - -Upd _loadTodos(CmdRepository repo, TodosModel model) { - var loadCmd = repo.loadTodosCmd((items) => OnTodosLoaded(items), - onError: (exc) => OnTodosLoadError(exc)); - var updatedModel = model.rebuild((b) => b - ..isLoading = true - ..loadingError = null); - return Upd(updatedModel, effects: loadCmd); -} - -Upd _onTodosLoaded( - TodosModel model, OnTodosLoaded msg) { - var updatedModel = model.rebuild((b) => b - ..isLoading = false - ..loadingError = null - ..items.clear() - ..items.addAll(msg.items.map(TodoModel.fromEntity))); - return Upd(updatedModel); -} - -Upd _onLoadingError( - TodosModel model, OnTodosLoadError msg) { - var updatedModel = model.rebuild((b) => b - ..isLoading = false - ..loadingError = msg.cause.toString()); - return Upd(updatedModel); -} - -Upd _toggleTodo( - CmdRepository repo, TodosModel model, UpdateTodo msg) { - var updatedTodo = msg.todo.rebuild((b) => b..complete = msg.value); - var updatedModel = _updateTodoItem(model, updatedTodo); - return Upd(updatedModel, effects: _saveTodosCmd(repo, updatedModel)); -} - -Upd _toggleAll( - CmdRepository repo, TodosModel model, ToggleAllMessage msg) { - var setComplete = model.items.any((x) => !x.complete); - var updatedModel = model.rebuild( - (b) => b.items.map((t) => t.rebuild((x) => x..complete = setComplete))); - return Upd(updatedModel, effects: _saveTodosCmd(repo, updatedModel)); -} - -TodosModel _removeTodo(TodosModel model, String id) => - model.rebuild((b) => b.items.where((x) => x.id != id)); - -Upd _onRepoEvent( - TodosModel model, OnTodoItemChanged msg) { - if (msg.updated != null) { - var updatedTodo = TodoModel.fromEntity(msg.updated); - return Upd(_updateTodoItem(model, updatedTodo)); - } - if (msg.created != null) { - var newItem = TodoModel.fromEntity(msg.created); - var updatedModel = model.rebuild((b) => b.items.add(newItem)); - return Upd(updatedModel); - } - if (msg.removed != null) { - var updatedModel = _removeTodo(model, msg.removed.id); - return Upd(updatedModel, - effects: snackbar.showUndoCmd(msg.removed.task, - () => UndoRemoveItem(TodoModel.fromEntity(msg.removed)))); - } - return Upd(model); -} - -TodosModel _updateTodoItem(TodosModel model, TodoModel updatedTodo) { - return model.rebuild( - (b) => b.items.map((x) => x.id == updatedTodo.id ? updatedTodo : x)); -} - -Cmd _saveTodosCmd(CmdRepository repo, TodosModel model) => - repo.saveAllCmd(model.items.map((t) => t.toEntity()).toList()); diff --git a/mvu/lib/todos/todos.dart b/mvu/lib/todos/todos.dart deleted file mode 100644 index 903fc6b2..00000000 --- a/mvu/lib/todos/todos.dart +++ /dev/null @@ -1,17 +0,0 @@ -library todos; - -import 'package:flutter/material.dart'; -import 'package:built_collection/built_collection.dart'; - -import 'package:mvu/common/repository_commands.dart' show CmdRepository; -import 'package:mvu/common/router.dart' as router; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:dartea/dartea.dart'; -import 'package:mvu/home/types.dart'; -import 'package:mvu/todos/types.dart'; -import 'package:mvu/common/todo_model.dart'; -import 'package:mvu/common/extra_actions_menu.dart' as menu; -import 'package:mvu/common/snackbar.dart' as snackbar; - -part 'state.dart'; -part 'view.dart'; diff --git a/mvu/lib/todos/types.dart b/mvu/lib/todos/types.dart deleted file mode 100644 index de511b23..00000000 --- a/mvu/lib/todos/types.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'package:built_value/built_value.dart'; -import 'package:built_collection/built_collection.dart'; - -import 'package:mvu/home/types.dart'; -import 'package:mvu/common/todo_model.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -part 'types.g.dart'; - -abstract class TodosModel implements Built { - bool get isLoading; - BuiltList get items; - VisibilityFilter get filter; - @nullable - String get loadingError; - - TodosModel._(); - factory TodosModel([void Function(TodosModelBuilder b) updates]) = - _$TodosModel; -} - -abstract class TodosMessage {} - -class LoadTodos implements TodosMessage {} - -class OnTodosLoaded implements TodosMessage { - final List items; - OnTodosLoaded(this.items); -} - -class OnTodosLoadError implements TodosMessage { - final Exception cause; - OnTodosLoadError(this.cause); -} - -class UpdateTodo implements TodosMessage { - final bool value; - final TodoModel todo; - UpdateTodo(this.value, this.todo); -} - -class RemoveTodo implements TodosMessage { - final TodoModel todo; - RemoveTodo(this.todo); -} - -class UndoRemoveItem implements TodosMessage { - final TodoModel item; - UndoRemoveItem(this.item); -} - -class FilterChanged implements TodosMessage { - final VisibilityFilter value; - FilterChanged(this.value); -} - -class ToggleAllMessage implements TodosMessage {} - -class CleareCompletedMessage implements TodosMessage {} - -class ShowDetailsMessage implements TodosMessage { - final TodoModel todo; - ShowDetailsMessage(this.todo); -} - -class OnTodoItemChanged implements TodosMessage { - final TodoEntity updated; - final TodoEntity removed; - final TodoEntity created; - OnTodoItemChanged({this.updated, this.removed, this.created}); -} diff --git a/mvu/lib/todos/types.g.dart b/mvu/lib/todos/types.g.dart deleted file mode 100644 index a47403fb..00000000 --- a/mvu/lib/todos/types.g.dart +++ /dev/null @@ -1,153 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'types.dart'; - -// ************************************************************************** -// BuiltValueGenerator -// ************************************************************************** - -// ignore_for_file: always_put_control_body_on_new_line -// ignore_for_file: annotate_overrides -// ignore_for_file: avoid_annotating_with_dynamic -// ignore_for_file: avoid_catches_without_on_clauses -// ignore_for_file: avoid_returning_this -// ignore_for_file: lines_longer_than_80_chars -// ignore_for_file: omit_local_variable_types -// ignore_for_file: prefer_expression_function_bodies -// ignore_for_file: sort_constructors_first -// ignore_for_file: unnecessary_const -// ignore_for_file: unnecessary_new -// ignore_for_file: test_types_in_equals - -class _$TodosModel extends TodosModel { - @override - final bool isLoading; - @override - final BuiltList items; - @override - final VisibilityFilter filter; - @override - final String loadingError; - - factory _$TodosModel([void Function(TodosModelBuilder b) updates]) => - (new TodosModelBuilder()..update(updates)).build(); - - _$TodosModel._({this.isLoading, this.items, this.filter, this.loadingError}) - : super._() { - if (isLoading == null) { - throw new BuiltValueNullFieldError('TodosModel', 'isLoading'); - } - if (items == null) { - throw new BuiltValueNullFieldError('TodosModel', 'items'); - } - if (filter == null) { - throw new BuiltValueNullFieldError('TodosModel', 'filter'); - } - } - - @override - TodosModel rebuild(void Function(TodosModelBuilder b) updates) => - (toBuilder()..update(updates)).build(); - - @override - TodosModelBuilder toBuilder() => new TodosModelBuilder()..replace(this); - - @override - bool operator ==(Object other) { - if (identical(other, this)) return true; - return other is TodosModel && - isLoading == other.isLoading && - items == other.items && - filter == other.filter && - loadingError == other.loadingError; - } - - @override - int get hashCode { - return $jf($jc( - $jc($jc($jc(0, isLoading.hashCode), items.hashCode), filter.hashCode), - loadingError.hashCode)); - } - - @override - String toString() { - return (newBuiltValueToStringHelper('TodosModel') - ..add('isLoading', isLoading) - ..add('items', items) - ..add('filter', filter) - ..add('loadingError', loadingError)) - .toString(); - } -} - -class TodosModelBuilder implements Builder { - _$TodosModel _$v; - - bool _isLoading; - bool get isLoading => _$this._isLoading; - set isLoading(bool isLoading) => _$this._isLoading = isLoading; - - ListBuilder _items; - ListBuilder get items => - _$this._items ??= new ListBuilder(); - set items(ListBuilder items) => _$this._items = items; - - VisibilityFilter _filter; - VisibilityFilter get filter => _$this._filter; - set filter(VisibilityFilter filter) => _$this._filter = filter; - - String _loadingError; - String get loadingError => _$this._loadingError; - set loadingError(String loadingError) => _$this._loadingError = loadingError; - - TodosModelBuilder(); - - TodosModelBuilder get _$this { - if (_$v != null) { - _isLoading = _$v.isLoading; - _items = _$v.items?.toBuilder(); - _filter = _$v.filter; - _loadingError = _$v.loadingError; - _$v = null; - } - return this; - } - - @override - void replace(TodosModel other) { - if (other == null) { - throw new ArgumentError.notNull('other'); - } - _$v = other as _$TodosModel; - } - - @override - void update(void Function(TodosModelBuilder b) updates) { - if (updates != null) updates(this); - } - - @override - _$TodosModel build() { - _$TodosModel _$result; - try { - _$result = _$v ?? - new _$TodosModel._( - isLoading: isLoading, - items: items.build(), - filter: filter, - loadingError: loadingError); - } catch (_) { - String _$failedField; - try { - _$failedField = 'items'; - items.build(); - } catch (e) { - throw new BuiltValueNestedFieldError( - 'TodosModel', _$failedField, e.toString()); - } - rethrow; - } - replace(_$result); - return _$result; - } -} diff --git a/mvu/lib/todos/view.dart b/mvu/lib/todos/view.dart deleted file mode 100644 index 40707793..00000000 --- a/mvu/lib/todos/view.dart +++ /dev/null @@ -1,130 +0,0 @@ -part of todos; - -Widget view( - BuildContext context, Dispatch dispatch, TodosModel model) { - return Container( - child: model.loadingError != null - ? _error(model.loadingError) - : model.isLoading ? _loading() : _list(dispatch, model), - ); -} - -Widget buildExtraActionsMenu( - Dispatch dispatch, TodosModel model) { - var allComplete = !model.items.any((x) => !x.complete); - return menu.buildExtraActionsMenu( - (act) => dispatch(_toMessage(act)), allComplete); -} - -Widget buildFilterMenu( - BuildContext context, Dispatch dispatch, TodosModel model) { - final defaultStyle = Theme.of(context).textTheme.body1; - final activeStyle = Theme.of(context) - .textTheme - .body1 - .copyWith(color: Theme.of(context).accentColor); - - return PopupMenuButton( - key: ArchSampleKeys.filterButton, - tooltip: ArchSampleLocalizations.of(context).filterTodos, - onSelected: (val) => dispatch(FilterChanged(val)), - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - key: ArchSampleKeys.allFilter, - value: VisibilityFilter.all, - child: Text( - ArchSampleLocalizations.of(context).showAll, - style: - model.filter == VisibilityFilter.all ? activeStyle : defaultStyle, - ), - ), - PopupMenuItem( - key: ArchSampleKeys.activeFilter, - value: VisibilityFilter.active, - child: Text( - ArchSampleLocalizations.of(context).showActive, - style: model.filter == VisibilityFilter.active - ? activeStyle - : defaultStyle, - ), - ), - PopupMenuItem( - key: ArchSampleKeys.completedFilter, - value: VisibilityFilter.completed, - child: Text( - ArchSampleLocalizations.of(context).showCompleted, - style: model.filter == VisibilityFilter.completed - ? activeStyle - : defaultStyle, - ), - ), - ], - icon: Icon(Icons.filter_list), - ); -} - -Widget _error(String error) { - return Center(child: Text(error)); -} - -Widget _loading() { - return Center( - child: CircularProgressIndicator( - key: ArchSampleKeys.todosLoading, - )); -} - -Widget _list(Dispatch dispatch, TodosModel model) { - var filteredList = model.items - .where((x) => - model.filter == VisibilityFilter.all || - (model.filter == VisibilityFilter.completed - ? x.complete - : !x.complete)) - .toList(); - - return ListView.builder( - key: ArchSampleKeys.todoList, - itemCount: filteredList.length, - itemBuilder: (BuildContext context, int index) => - _item(context, dispatch, filteredList[index], model), - ); -} - -Widget _item(BuildContext context, Dispatch dispatch, - TodoModel model, TodosModel todos) { - return Dismissible( - key: ArchSampleKeys.todoItem(model.id), - onDismissed: (_) => dispatch(RemoveTodo(model)), - child: ListTile( - onTap: () => dispatch(ShowDetailsMessage(model)), - leading: Checkbox( - key: ArchSampleKeys.todoItemCheckbox(model.id), - value: model.complete, - onChanged: (val) => dispatch(UpdateTodo(val, model)), - ), - title: Text( - model.task, - key: ArchSampleKeys.todoItemTask(model.id), - style: Theme.of(context).textTheme.title, - ), - subtitle: Text( - model.note, - key: ArchSampleKeys.todoItemNote(model.id), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, - ), - ), - ); -} - -TodosMessage _toMessage(menu.ExtraAction action) { - switch (action) { - case menu.ExtraAction.toggleAll: - return ToggleAllMessage(); - case menu.ExtraAction.clearCompleted: - default: - return CleareCompletedMessage(); - } -} diff --git a/mvu/mvu_todo.png b/mvu/mvu_todo.png deleted file mode 100644 index 4674dff9..00000000 Binary files a/mvu/mvu_todo.png and /dev/null differ diff --git a/mvu/pubspec.yaml b/mvu/pubspec.yaml deleted file mode 100644 index df6c4155..00000000 --- a/mvu/pubspec.yaml +++ /dev/null @@ -1,81 +0,0 @@ -name: mvu -description: A new Flutter project. - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 - -environment: - sdk: ">=2.1.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - built_value: ^6.3.1 - built_collection: ^4.1.0 - dartea: "^0.5.5" - todos_app_core: - path: ../todos_app_core - todos_repository_local_storage: - path: ../todos_repository_local_storage - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_driver: - sdk: flutter - test: - build_runner: ^1.2.8 - built_value_generator: ^6.1.0 - integration_tests: - path: ../integration_tests - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/mvu/test/all_tests.dart b/mvu/test/all_tests.dart deleted file mode 100644 index 45a4ddeb..00000000 --- a/mvu/test/all_tests.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'details_screen_test.dart' as details_screen; -import 'edit_screen_test.dart' as edit_screen; -import 'home_screen_test.dart' as home_screen; -import 'repository_commads_test.dart' as repository_commands; -import 'stats_screen_test.dart' as stats_screen; -import 'todos_screen_test.dart' as todos_screen; - -void main() { - details_screen.main(); - edit_screen.main(); - home_screen.main(); - repository_commands.main(); - stats_screen.main(); - todos_screen.main(); -} diff --git a/mvu/test/cmd_runner.dart b/mvu/test/cmd_runner.dart deleted file mode 100644 index 98fcf4d9..00000000 --- a/mvu/test/cmd_runner.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:dartea/dartea.dart'; - -///run side-effects and save produced messages to the [producedMessages] list -class CmdRunner { - final producedMessages = []; - - void run(Cmd cmd) { - for (var effect in cmd) { - effect((m) => producedMessages.add(m)); - } - } - - void invalidate() => producedMessages.clear(); -} diff --git a/mvu/test/data.dart b/mvu/test/data.dart deleted file mode 100644 index 3ae483c6..00000000 --- a/mvu/test/data.dart +++ /dev/null @@ -1,136 +0,0 @@ -import 'dart:async'; - -import 'package:mvu/common/repository_commands.dart'; -import 'package:dartea/dartea.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -List createTodos({bool complete}) => [ - TodoEntity('Buy milk', '1', 'soy', complete ?? false), - TodoEntity('Buy bread', '2', 'italian one', complete ?? true), - TodoEntity('Buy meat', '3', 'or chicken', complete ?? false), - TodoEntity('Buy water', '4', 'carbonated and still', complete ?? true), - TodoEntity('Read book', '5', 'interesting one', complete ?? false), - TodoEntity('Watch football', '6', '', complete ?? true), - TodoEntity('Sleep', '7', 'well', complete ?? false), - ]; - -List createTodosForStats(int activeCount, int completedCount) { - final result = []; - for (var i = 0; i < activeCount; i++) { - var todo = TodoEntity('todo $i', '$i', 'note for todo #$i', false); - result.add(todo); - } - var totalLength = result.length + completedCount; - for (var i = result.length; i < totalLength; i++) { - var todo = TodoEntity('todo $i', '$i', 'note for todo #$i', true); - result.add(todo); - } - return result; -} - -class InMemoryTodosRepository implements TodosRepository { - final items = []; - final bool isBrokern; - InMemoryTodosRepository( - {Iterable initialItems, this.isBrokern = false}) { - if (initialItems != null) { - items.addAll(initialItems); - } - } - @override - Future> loadTodos() { - if (isBrokern) { - throw Exception('repo is broken'); - } - return Future.value(items.toList()); - } - - @override - Future saveTodos(List todos) => Future.sync(() { - items.clear(); - items.addAll(todos); - }); -} - -class TestTodosCmdRepository implements CmdRepository { - final createdEffects = []; - - @override - Cmd createCmd( - T Function(TodoEntity todo) onSuccess, String task, String note) { - final entity = TodoEntity(task, 'new_id', note, false); - createdEffects.add(CreateTodoEffect(task, note)); - return Cmd.ofFunc(() => entity, onSuccess: onSuccess); - } - - @override - Cmd loadTodosCmd(T Function(List items) onSuccess, - {T Function(Exception exc) onError}) { - final todos = createTodos(); - createdEffects.add(LoadTodosEffect()); - return Cmd.ofFunc(() => todos, onSuccess: onSuccess); - } - - @override - Cmd removeCmd(TodoEntity todo, {T Function() onSuccess}) { - createdEffects.add(RemoveTodoEffect(todo)); - return Cmd.ofAction(() {}, onSuccess: onSuccess); - } - - @override - Cmd saveAllCmd(List entities, {T Function() onSuccess}) { - createdEffects.add(SaveAllTodosEffect(entities)); - return Cmd.ofAction(() {}, onSuccess: onSuccess); - } - - @override - Cmd saveCmd(TodoEntity todo, {T Function() onSuccess}) { - createdEffects.add(SaveTodoEffect(todo)); - return Cmd.ofAction(() {}, onSuccess: onSuccess); - } - - @override - Cmd updateDetailsCmd(T Function(TodoEntity todo) onSuccess, String id, - String task, String note) { - createdEffects.add(UpdateDetailsEffect(id, task, note)); - final updatedTodo = TodoEntity(task, id, note, false); - return Cmd.ofFunc(() => updatedTodo, onSuccess: onSuccess); - } - - void invalidate() => createdEffects.clear(); - - @override - Stream get events => events.asBroadcastStream(); -} - -abstract class RepoEffect {} - -class LoadTodosEffect implements RepoEffect {} - -class CreateTodoEffect implements RepoEffect { - final String task; - final String note; - CreateTodoEffect(this.task, this.note); -} - -class RemoveTodoEffect implements RepoEffect { - final TodoEntity entity; - RemoveTodoEffect(this.entity); -} - -class SaveAllTodosEffect implements RepoEffect { - final List entities; - SaveAllTodosEffect(this.entities); -} - -class SaveTodoEffect implements RepoEffect { - final TodoEntity entity; - SaveTodoEffect(this.entity); -} - -class UpdateDetailsEffect implements RepoEffect { - final String id; - final String task; - final String note; - UpdateDetailsEffect(this.id, this.task, this.note); -} diff --git a/mvu/test/details_screen_test.dart b/mvu/test/details_screen_test.dart deleted file mode 100644 index 05ff9bc4..00000000 --- a/mvu/test/details_screen_test.dart +++ /dev/null @@ -1,73 +0,0 @@ -import 'package:test/test.dart'; - -import 'package:mvu/details/details.dart'; -import 'package:mvu/details/types.dart'; -import 'package:mvu/common/todo_model.dart'; -import 'data.dart'; -import 'cmd_runner.dart'; - -void main() { - group('Details screen ->', () { - CmdRunner _cmdRunner; - TestTodosCmdRepository _cmdRepo; - - setUp(() { - _cmdRunner = CmdRunner(); - _cmdRepo = TestTodosCmdRepository(); - }); - - test('init', () { - var todo = createTodos().map((x) => TodoModel.fromEntity(x)).first; - var model = init(todo).model; - - expect(model.todo, equals(todo)); - }); - - test('ToggleCompleted: todo state is changed', () { - var todo = createTodos().map((x) => TodoModel.fromEntity(x)).first; - var model = init(todo).model; - - final updResult = update(_cmdRepo, ToggleCompleted(), model); - final updatedModel = updResult.model; - _cmdRunner.run(updResult.effects); - - expect(updatedModel.todo.complete, isNot(todo.complete)); - expect( - _cmdRepo.createdEffects, - orderedEquals([ - predicate((x) => - x is SaveTodoEffect && x.entity == updatedModel.todo.toEntity()) - ])); - expect(_cmdRunner.producedMessages, isEmpty); - }); - - test('Remove: model is not changed', () { - var todo = createTodos().map((x) => TodoModel.fromEntity(x)).first; - var model = init(todo).model; - - final updateResult = update(_cmdRepo, Remove(), model); - final updatedModel = updateResult.model; - _cmdRunner.run(updateResult.effects); - - expect(updatedModel, equals(model)); - expect( - _cmdRepo.createdEffects, - orderedEquals([ - predicate((x) => - x is RemoveTodoEffect && - x.entity == updatedModel.todo.toEntity()) - ])); - expect(_cmdRunner.producedMessages, isEmpty); - }); - - test('Edit: model is not changed', () { - var todo = createTodos().map((x) => TodoModel.fromEntity(x)).first; - var model = init(todo).model; - - var updateResult = update(_cmdRepo, Edit(), model); - - expect(updateResult.model, equals(model)); - expect(updateResult.effects, isNotEmpty); - }); - }); -} diff --git a/mvu/test/edit_screen_test.dart b/mvu/test/edit_screen_test.dart deleted file mode 100644 index fc8d8b8e..00000000 --- a/mvu/test/edit_screen_test.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:test/test.dart'; - -import 'package:mvu/edit/edit.dart'; -import 'package:mvu/edit/types.dart'; -import 'cmd_runner.dart'; -import 'data.dart'; - -void main() { - group('Edit screen ->', () { - CmdRunner _cmdRunner; - TestTodosCmdRepository _cmdRepo; - - setUp(() { - _cmdRunner = CmdRunner(); - _cmdRepo = TestTodosCmdRepository(); - }); - - test('init', () { - var todo = createTodos().first; - var model = init(todo).model; - - expect(model.id, equals(todo.id)); - expect(model.note.text, equals(todo.note)); - expect(model.task.text, equals(todo.task)); - }); - - test('OnSaved: model is not changed, has effects', () { - var todo = createTodos().first; - var model = init(todo).model; - - var upd = update(_cmdRepo, OnSaved(todo), model); - - expect(upd.model, equals(model)); - expect(upd.effects, isNotEmpty); - }); - - test('Save: if task is empty no side effects', () { - var model = init(null).model; - - var updateResult = update(_cmdRepo, Save(), model); - - expect(updateResult.model, equals(model)); - expect(updateResult.effects, isEmpty); - }); - - test('Save: if task is not empty has side effects', () { - var todo = createTodos().first; - var model = init(todo).model; - final updatedNote = todo.note + '_changed'; - final updatedTask = todo.task + '_changed'; - model.note.text = updatedNote; - model.task.text = updatedTask; - - var updateResult = update(_cmdRepo, Save(), model); - _cmdRunner.run(updateResult.effects); - - expect(updateResult.model, equals(model)); - expect(updateResult.effects, isNotEmpty); - expect( - _cmdRepo.createdEffects, - orderedEquals([ - predicate((x) => - x is UpdateDetailsEffect && - x.id == model.id && - x.note == updatedNote && - x.task == updatedTask) - ])); - expect( - _cmdRunner.producedMessages, - orderedEquals([ - predicate((x) => - x is OnSaved && - x.todo.id == model.id && - x.todo.note == updatedNote && - x.todo.task == updatedTask) - ])); - }); - }); -} diff --git a/mvu/test/home_screen_test.dart b/mvu/test/home_screen_test.dart deleted file mode 100644 index ccf959e8..00000000 --- a/mvu/test/home_screen_test.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:test/test.dart'; - -import 'package:mvu/home/home.dart'; -import 'package:mvu/home/types.dart'; - -void main() { - group('Home screen ->', () { - test('init', () { - for (var tab in AppTab.values) { - var initResult = init(tab); - expect(initResult.model.body.tag, equals(tab)); - } - }); - - test('TabChangedMessage: tab is changed', () { - var currentTab = AppTab.todos; - var model = init(currentTab).model; - expect(model.body.tag, equals(currentTab)); - - currentTab = AppTab.stats; - var updatedModel = update(TabChangedMessage(currentTab), model).model; - expect(updatedModel.body.tag, equals(currentTab)); - - currentTab = AppTab.todos; - updatedModel = update(TabChangedMessage(currentTab), model).model; - expect(updatedModel.body.tag, equals(currentTab)); - }); - - test('TabChangedMessage: model is not changed if current and tab are same', - () { - var currentTab = AppTab.todos; - var model = init(currentTab).model; - expect(model.body.tag, equals(currentTab)); - var updatedModel = update(TabChangedMessage(currentTab), model).model; - expect(updatedModel, equals(model)); - }); - }); -} diff --git a/mvu/test/repository_commads_test.dart b/mvu/test/repository_commads_test.dart deleted file mode 100644 index b76c73fa..00000000 --- a/mvu/test/repository_commads_test.dart +++ /dev/null @@ -1,120 +0,0 @@ -import 'package:test/test.dart'; - -import 'package:mvu/common/repository_commands.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; -import 'cmd_runner.dart'; -import 'data.dart'; - -void main() { - InMemoryTodosRepository todosRepository; - CmdRepository brokenCmdRepository; - CmdRepository cmdRepository; - CmdRunner runner; - setUp(() { - todosRepository = InMemoryTodosRepository(initialItems: createTodos()); - brokenCmdRepository = - TodosCmdRepository(InMemoryTodosRepository(isBrokern: true)); - cmdRepository = TodosCmdRepository(todosRepository); - runner = CmdRunner(); - }); - - group('repository commands', () { - test('load todos (success)', () { - final loadCmd = cmdRepository.loadTodosCmd(expectAsync1((items) { - expect(items, orderedEquals(todosRepository.items)); - return OnLoadSuccess(items); - }), onError: expectAsync1((e) => OnLoadError(e), count: 0)); - - runner.run(loadCmd); - }); - - test('load todos (error)', () { - final loadCmd = brokenCmdRepository.loadTodosCmd( - expectAsync1((items) => OnLoadSuccess(items), count: 0), - onError: expectAsync1((e) => OnLoadError(e), count: 1)); - - runner.run(loadCmd); - }); - - test('save todos', () { - final items = todosRepository.items.take(3).toList(); - final saveCmd = - cmdRepository.saveAllCmd(items, onSuccess: expectAsync0(() { - expect(todosRepository.items, orderedEquals(items)); - return null; - })); - - runner.run(saveCmd); - }); - - test('remove todo', () { - final itemToRemove = todosRepository.items.first; - final cmd = cmdRepository.removeCmd(itemToRemove, - onSuccess: expectAsync0(() { - expect(todosRepository.items, isNot(contains(itemToRemove))); - return null; - })); - - runner.run(cmd); - }); - - test('save todo', () { - final firstItem = todosRepository.items.first; - final updated = TodoEntity( - firstItem.task, firstItem.id, firstItem.note, !firstItem.complete); - - final cmd = - cmdRepository.saveCmd(updated, onSuccess: expectAsync0(() { - expect(todosRepository.items, contains(updated)); - return null; - })); - - runner.run(cmd); - }); - - test('create todo', () { - final task = 'Write unit tests'; - final note = 'and integration'; - - final cmd = cmdRepository.createCmd(expectAsync1((x) { - expect( - todosRepository.items, - anyElement(predicate( - (x) => x.note == note && x.task == task && !x.complete))); - return null; - }), task, note); - - runner.run(cmd); - }); - - test('update details', () { - final idToUpdate = todosRepository.items.first.id; - final task = 'Write unit tests'; - final note = 'and integration'; - - final cmd = cmdRepository.updateDetailsCmd(expectAsync1((x) { - expect( - todosRepository.items, - anyElement(predicate((x) => - x.id == idToUpdate && x.note == note && x.task == task))); - return null; - }), idToUpdate, task, note); - - runner.run(cmd); - }); - }); -} - -abstract class Message {} - -class OnLoadSuccess implements Message { - final List items; - OnLoadSuccess(this.items); -} - -class OnLoadError implements Message { - final Exception error; - OnLoadError(this.error); -} - -class OnSaveSuccess implements Message {} diff --git a/mvu/test/stats_screen_test.dart b/mvu/test/stats_screen_test.dart deleted file mode 100644 index b64bffde..00000000 --- a/mvu/test/stats_screen_test.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'package:mvu/common/todo_model.dart'; -import 'package:mvu/stats/stats.dart'; -import 'package:mvu/stats/types.dart'; -import 'package:test/test.dart'; - -import 'cmd_runner.dart'; -import 'data.dart'; - -void main() { - group('Home screen "Stats" ->', () { - CmdRunner _cmdRunner; - TestTodosCmdRepository _cmdRepo; - - setUp(() { - _cmdRunner = CmdRunner(); - _cmdRepo = TestTodosCmdRepository(); - }); - - test('init', () { - final initResult = init(); - final model = initResult.model; - final initEffects = initResult.effects; - _cmdRunner.run(initEffects); - - expect(model.activeCount, 0); - expect(model.completedCount, 0); - expect(model.loading, isFalse); - expect(initEffects, isNotEmpty); - expect(_cmdRunner.producedMessages, - orderedEquals([TypeMatcher()])); - }); - - test('LoadStats: model is in loading state', () { - var model = init().model; - - final upd = update(_cmdRepo, LoadStats(), model); - final updatedModel = upd.model; - final effects = upd.effects; - _cmdRunner.run(effects); - - expect(updatedModel.loading, isTrue); - expect(effects, isNotEmpty); - expect(_cmdRunner.producedMessages, - orderedEquals([TypeMatcher()])); - expect(_cmdRepo.createdEffects, - orderedEquals([TypeMatcher()])); - }); - - test('OnStatsLoaded: stats is displayed', () { - var model = init().model; - var activeCount = 5, completedCount = 8; - var items = createTodosForStats(activeCount, completedCount); - - var updatedModel = update(_cmdRepo, OnStatsLoaded(items), model).model; - - expect(updatedModel.loading, isFalse); - expect(updatedModel.activeCount, activeCount); - expect(updatedModel.completedCount, completedCount); - }); - - test('ToggleAllMessage(false->true): stats is updated', () { - var model = init().model; - var items = createTodos(complete: false); - var upd = update(_cmdRepo, OnStatsLoaded(items), model); - var updatedModel = upd.model; - upd = update(_cmdRepo, ToggleAllMessage(), updatedModel); - updatedModel = upd.model; - _cmdRunner.run(upd.effects); - - expect(updatedModel.activeCount, 0); - expect(updatedModel.completedCount, items.length); - expect(upd.effects, isNotEmpty); - expect(_cmdRepo.createdEffects, - orderedEquals([TypeMatcher()])); - }); - - test('ToggleAllMessage(true->false): stats is updated', () { - var model = init().model; - var items = createTodos(complete: true); - var updatedModel = update(_cmdRepo, OnStatsLoaded(items), model).model; - - updatedModel = update(_cmdRepo, ToggleAllMessage(), updatedModel).model; - - expect(updatedModel.activeCount, items.length); - expect(updatedModel.completedCount, 0); - }); - - test('ToggleAllMessage(partially): stats is updated', () { - var model = init().model; - var activeCount = 3, completedCount = 6; - var items = createTodosForStats(activeCount, completedCount); - var updatedModel = update(_cmdRepo, OnStatsLoaded(items), model).model; - - updatedModel = update(_cmdRepo, ToggleAllMessage(), updatedModel).model; - - expect(updatedModel.activeCount, 0); - expect(updatedModel.completedCount, items.length); - expect(updatedModel.items, - everyElement(predicate((x) => x.complete))); - }); - - test('CleareCompletedMessage: stats is updated', () { - var model = init().model; - var activeCount = 3, completedCount = 6; - var items = createTodosForStats(activeCount, completedCount); - var updatedModel = update(_cmdRepo, OnStatsLoaded(items), model).model; - - final upd = update(_cmdRepo, CleareCompletedMessage(), updatedModel); - updatedModel = upd.model; - _cmdRunner.run(upd.effects); - - expect(updatedModel.activeCount, activeCount); - expect(updatedModel.completedCount, 0); - expect(updatedModel.items, - everyElement(predicate((x) => !x.complete))); - expect(upd.effects, isNotEmpty); - expect(_cmdRepo.createdEffects, - orderedEquals([TypeMatcher()])); - }); - }); -} diff --git a/mvu/test/todos_screen_test.dart b/mvu/test/todos_screen_test.dart deleted file mode 100644 index 712d41de..00000000 --- a/mvu/test/todos_screen_test.dart +++ /dev/null @@ -1,234 +0,0 @@ -import 'package:built_collection/built_collection.dart'; -import 'package:mvu/common/todo_model.dart'; -import 'package:mvu/home/types.dart' show VisibilityFilter; -import 'package:mvu/todos/todos.dart'; -import 'package:mvu/todos/types.dart'; -import 'package:test/test.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; - -import 'cmd_runner.dart'; -import 'data.dart'; - -CmdRunner _cmdRunner; -TestTodosCmdRepository _cmdRepo; - -void main() { - group('Home screen "Todos" ->', () { - setUp(() { - _cmdRunner = CmdRunner(); - _cmdRepo = TestTodosCmdRepository(); - }); - - test('init', () { - for (var filter in VisibilityFilter.values) { - var initResult = init(filter); - final model = initResult.model; - _cmdRunner.run(initResult.effects); - - expect(model.filter, equals(filter)); - expect(model.isLoading, isFalse); - expect(model.loadingError, anyOf(isNull, isEmpty)); - expect(model.items, isEmpty); - expect(initResult.effects, isNotEmpty); - expect(_cmdRunner.producedMessages, - orderedEquals([TypeMatcher()])); - - _cmdRunner.invalidate(); - } - }); - - test('LoadTodos: model is in loading state', () { - var model = init(VisibilityFilter.all).model; - var upd = update(_cmdRepo, LoadTodos(), model); - final updatedModel = upd.model; - _cmdRunner.run(upd.effects); - - expect(updatedModel.isLoading, isTrue); - expect(upd.effects, isNotEmpty); - expect(_cmdRepo.createdEffects, - orderedEquals([TypeMatcher()])); - expect(_cmdRunner.producedMessages, - orderedEquals([TypeMatcher()])); - }); - - test('OnTodosLoaded: todos are loaded', () { - var model = init(VisibilityFilter.all).model; - var items = createTodos(); - var upd = update(_cmdRepo, OnTodosLoaded(items), model); - final updatedModel = upd.model; - - expect(updatedModel.isLoading, isFalse); - expect(updatedModel.items.map((x) => x.toEntity()), orderedEquals(items)); - expect(upd.effects, isEmpty); - }); - - test('OnTodosLoadError: model is in error state', () { - var model = init(VisibilityFilter.all).model; - var cause = Exception('No connection'); - var upd = update(_cmdRepo, OnTodosLoadError(cause), model); - final updatedModel = upd.model; - - expect(updatedModel.isLoading, isFalse); - expect(updatedModel.loadingError, equals(cause.toString())); - expect(upd.effects, isEmpty); - }); - - test('UpdateTodo: toggle todo state', () { - var items = createTodos().map((x) => TodoModel.fromEntity(x)); - var model = _createWith(items); - - var repoEffectsMatchers = []; - for (var item in items) { - var upd = update(_cmdRepo, UpdateTodo(!item.complete, item), model); - final updatedModel = upd.model; - var updatedTodo = updatedModel.items.firstWhere( - (x) => x.id == item.id, - orElse: () => null, - ); - _cmdRunner.run(upd.effects); - - expect(updatedModel.items.length, items.length); - expect(updatedTodo, isNotNull); - expect(updatedTodo.complete, equals(!item.complete)); - expect(upd.effects, isNotEmpty); - repoEffectsMatchers.add(TypeMatcher()); - } - expect(_cmdRepo.createdEffects, orderedEquals(repoEffectsMatchers)); - }); - - test('RemoveTodo: item is removed', () { - var items = createTodos().map((x) => TodoModel.fromEntity(x)); - var model = _createWith(items); - - final repoEffectsMatchers = []; - for (var item in items) { - var upd = update(_cmdRepo, RemoveTodo(item), model); - final updatedModel = upd.model; - _cmdRunner.run(upd.effects); - - expect(updatedModel.items, isNot(contains(item))); - repoEffectsMatchers.add(TypeMatcher()); - } - expect(_cmdRepo.createdEffects, orderedEquals(repoEffectsMatchers)); - }); - - test('UndoRemoveItem: undo removing', () { - var items = createTodos().map((x) => TodoModel.fromEntity(x)); - var model = _createWith(items); - - for (var itemToRemove in items) { - var upd = update(_cmdRepo, RemoveTodo(itemToRemove), model); - final updatedModel = upd.model; - expect(updatedModel.items, isNot(contains(itemToRemove))); - final undoUpd = - update(_cmdRepo, UndoRemoveItem(itemToRemove), updatedModel); - final undoModel = undoUpd.model; - expect(undoModel.items, contains(itemToRemove)); - } - }); - - test('FilterChanged: model with provided filter', () { - var currentFilter = VisibilityFilter.all; - var model = init(currentFilter).model; - expect(model.filter, equals(currentFilter)); - - for (var filter in VisibilityFilter.values) { - var upd = update(_cmdRepo, FilterChanged(filter), model); - expect(upd.model.filter, equals(filter)); - } - }); - - test('ToggleAllMessage: mark all as complete', () { - var items = - createTodos(complete: false).map((x) => TodoModel.fromEntity(x)); - var model = _createWith(items); - - var upd = update(_cmdRepo, ToggleAllMessage(), model); - _cmdRunner.run(upd.effects); - - expect(upd.model.items, - everyElement(predicate((x) => x.complete))); - expect(_cmdRepo.createdEffects, - orderedEquals([TypeMatcher()])); - }); - - test('ToggleAllMessage: mark all as incomplete', () { - var items = - createTodos(complete: true).map((x) => TodoModel.fromEntity(x)); - var model = _createWith(items); - - var upd = update(_cmdRepo, ToggleAllMessage(), model); - - expect(upd.model.items, - everyElement(predicate((x) => !x.complete))); - }); - - test('CleareCompletedMessage: remove all completed todos', () { - var items = createTodos().map((x) => TodoModel.fromEntity(x)); - var model = _createWith(items); - expect(model.items, anyElement(predicate((x) => x.complete))); - - var upd = update(_cmdRepo, CleareCompletedMessage(), model); - _cmdRunner.run(upd.effects); - - expect(upd.model.items, - everyElement(predicate((x) => !x.complete))); - expect(_cmdRepo.createdEffects, - orderedEquals([TypeMatcher()])); - }); - - test('ShowDetailsMessage: model is not changed', () { - var items = createTodos().map((x) => TodoModel.fromEntity(x)); - var model = _createWith(items); - - var upd = update(_cmdRepo, ShowDetailsMessage(items.first), model); - - expect(upd.model, equals(model)); - }); - - test('OnTodoItemChanged: item is updated', () { - var items = createTodos().map((x) => TodoModel.fromEntity(x)); - var model = _createWith(items); - - var itemToUpdate = items.first.rebuild((b) => b - ..complete = !b.complete - ..note = b.note + 'v1' - ..task = b.task + 'v1'); - - var upd = update( - _cmdRepo, OnTodoItemChanged(updated: itemToUpdate.toEntity()), model); - var updatedItem = - upd.model.items.firstWhere((x) => x.id == itemToUpdate.id); - - expect(itemToUpdate, equals(updatedItem)); - }); - - test('OnTodoItemChanged: item is removed', () { - var items = createTodos().map((x) => TodoModel.fromEntity(x)); - var model = _createWith(items); - - var itemToRemove = items.first; - - var upd = update( - _cmdRepo, OnTodoItemChanged(removed: itemToRemove.toEntity()), model); - - expect(upd.model.items, isNot(contains(itemToRemove))); - }); - - test('OnTodoItemChanged: item is created', () { - var items = createTodos().map((x) => TodoModel.fromEntity(x)); - var model = _createWith(items); - - var newItem = TodoEntity('New one', '11234', 'some note', false); - - var upd = update(_cmdRepo, OnTodoItemChanged(created: newItem), model); - - expect(upd.model.items, contains(TodoModel.fromEntity(newItem))); - }); - }); -} - -TodosModel _createWith(Iterable items) => TodosModel((b) => b - ..filter = VisibilityFilter.all - ..isLoading = false - ..items = BuiltList(items).toBuilder()); diff --git a/mvu/test/widget_test.dart b/mvu/test/widget_test.dart deleted file mode 100644 index f2142212..00000000 --- a/mvu/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:mvu/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/mvu/test_driver/todo_app.dart b/mvu/test_driver/todo_app.dart deleted file mode 100644 index 070a0c85..00000000 --- a/mvu/test_driver/todo_app.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:flutter_driver/driver_extension.dart'; -import 'package:mvu/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/mvu/test_driver/todo_app_test.dart b/mvu/test_driver/todo_app_test.dart deleted file mode 100644 index 1c5a586c..00000000 --- a/mvu/test_driver/todo_app_test.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/redux/.metadata b/redux/.metadata index 361e1e4c..05a8ab44 100644 --- a/redux/.metadata +++ b/redux/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: 18cd7a3601bcffb36fdf2f679f763b5e827c2e8e - channel: beta + revision: "05db9689081f091050f01aed79f04dce0c750154" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: android + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: ios + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: linux + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: macos + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: web + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: windows + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/redux/analysis_options.yaml b/redux/analysis_options.yaml new file mode 100644 index 00000000..134f2137 --- /dev/null +++ b/redux/analysis_options.yaml @@ -0,0 +1,34 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# 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 +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + # The lint rules applied to this project can be customized in the + # 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 + # and their documentation is published at https://dart.dev/lints. + # + # 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 + # 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 + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/redux/android/.gitignore b/redux/android/.gitignore index bc2100d8..be3943c9 100644 --- a/redux/android/.gitignore +++ b/redux/android/.gitignore @@ -5,3 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/redux/android/app/build.gradle b/redux/android/app/build.gradle deleted file mode 100644 index 73f22ada..00000000 --- a/redux/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.redux" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/redux/android/app/build.gradle.kts b/redux/android/app/build.gradle.kts new file mode 100644 index 00000000..bb3748cf --- /dev/null +++ b/redux/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.redux_sample" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.redux_sample" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/redux/android/app/src/debug/AndroidManifest.xml b/redux/android/app/src/debug/AndroidManifest.xml index f404de4d..399f6981 100644 --- a/redux/android/app/src/debug/AndroidManifest.xml +++ b/redux/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/redux/android/app/src/main/AndroidManifest.xml b/redux/android/app/src/main/AndroidManifest.xml index e249cc72..29735f54 100644 --- a/redux/android/app/src/main/AndroidManifest.xml +++ b/redux/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,25 @@ - - + + + @@ -27,4 +31,15 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + diff --git a/redux/android/app/src/main/kotlin/com/example/redux/MainActivity.kt b/redux/android/app/src/main/kotlin/com/example/redux/MainActivity.kt deleted file mode 100644 index 30266c3c..00000000 --- a/redux/android/app/src/main/kotlin/com/example/redux/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.redux - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/redux/android/app/src/main/kotlin/com/example/redux_sample/MainActivity.kt b/redux/android/app/src/main/kotlin/com/example/redux_sample/MainActivity.kt new file mode 100644 index 00000000..1afad812 --- /dev/null +++ b/redux/android/app/src/main/kotlin/com/example/redux_sample/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.redux_sample + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/redux/android/app/src/main/res/drawable-v21/launch_background.xml b/redux/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/redux/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/redux/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/redux/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index a3f285f9..db77bb4b 100644 Binary files a/redux/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/redux/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/redux/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/redux/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 5e6f3ac6..17987b79 100644 Binary files a/redux/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/redux/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/redux/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/redux/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 144d60be..09d43914 100644 Binary files a/redux/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/redux/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/redux/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/redux/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index deafae2d..d5f1c8d3 100644 Binary files a/redux/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/redux/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/redux/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/redux/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index d5614ac8..4d6372ee 100644 Binary files a/redux/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/redux/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/redux/android/app/src/main/res/values-night/styles.xml b/redux/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/redux/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/redux/android/app/src/main/res/values/styles.xml b/redux/android/app/src/main/res/values/styles.xml index 00fa4417..cb1ef880 100644 --- a/redux/android/app/src/main/res/values/styles.xml +++ b/redux/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ - + + diff --git a/redux/android/app/src/profile/AndroidManifest.xml b/redux/android/app/src/profile/AndroidManifest.xml index f404de4d..399f6981 100644 --- a/redux/android/app/src/profile/AndroidManifest.xml +++ b/redux/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/redux/android/build.gradle b/redux/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/redux/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/redux/android/build.gradle.kts b/redux/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/redux/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/redux/android/gradle.properties b/redux/android/gradle.properties index 38c8d454..f018a618 100644 --- a/redux/android/gradle.properties +++ b/redux/android/gradle.properties @@ -1,4 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/redux/android/gradle/wrapper/gradle-wrapper.properties b/redux/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..ac3b4792 100644 --- a/redux/android/gradle/wrapper/gradle-wrapper.properties +++ b/redux/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/redux/android/gradlew.bat b/redux/android/gradlew.bat index 8a0b282a..aec99730 100644 --- a/redux/android/gradlew.bat +++ b/redux/android/gradlew.bat @@ -1,90 +1,90 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/redux/android/settings.gradle b/redux/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/redux/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/redux/android/settings.gradle.kts b/redux/android/settings.gradle.kts new file mode 100644 index 00000000..fb605bc8 --- /dev/null +++ b/redux/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/redux/integration_test/app_test.dart b/redux/integration_test/app_test.dart new file mode 100644 index 00000000..75488cc5 --- /dev/null +++ b/redux/integration_test/app_test.dart @@ -0,0 +1,29 @@ +import 'package:integration_tests/integration_tests.dart' as integration_tests; +import 'package:redux/redux.dart'; +import 'package:redux_sample/app.dart'; +import 'package:redux_sample/middleware/store_todos_middleware.dart'; +import 'package:redux_sample/models/app_state.dart'; +import 'package:redux_sample/reducers/app_state_reducer.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; + +void main() { + integration_tests.run( + appBuilder: () async { + return ReduxApp( + store: Store( + appReducer, + initialState: AppState.loading(), + middleware: createStoreTodosMiddleware( + LocalStorageRepository( + localStorage: KeyValueStorage( + 'redux_test_${DateTime.now().toIso8601String()}', + await SharedPreferences.getInstance(), + ), + ), + ), + ), + ); + }, + ); +} diff --git a/redux/ios/.gitignore b/redux/ios/.gitignore index e96ef602..7a7f9873 100644 --- a/redux/ios/.gitignore +++ b/redux/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/redux/ios/Flutter/AppFrameworkInfo.plist b/redux/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f78..1dc6cf76 100644 --- a/redux/ios/Flutter/AppFrameworkInfo.plist +++ b/redux/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 13.0 diff --git a/redux/ios/Flutter/Debug.xcconfig b/redux/ios/Flutter/Debug.xcconfig index e8efba11..ec97fc6f 100644 --- a/redux/ios/Flutter/Debug.xcconfig +++ b/redux/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/redux/ios/Flutter/Release.xcconfig b/redux/ios/Flutter/Release.xcconfig index 399e9340..c4855bfe 100644 --- a/redux/ios/Flutter/Release.xcconfig +++ b/redux/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/redux/ios/Podfile b/redux/ios/Podfile index b30a428b..620e46eb 100644 --- a/redux/ios/Podfile +++ b/redux/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -10,81 +10,34 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - generated_key_values + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' +flutter_ios_podfile_setup - # Plugin Pods +target 'Runner' do + use_frameworks! - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths end end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/redux/ios/Podfile.lock b/redux/ios/Podfile.lock deleted file mode 100644 index 60cb72ff..00000000 --- a/redux/ios/Podfile.lock +++ /dev/null @@ -1,34 +0,0 @@ -PODS: - - Flutter (1.0.0) - - key_value_store_flutter (0.0.1): - - Flutter - - path_provider (0.0.1): - - Flutter - - shared_preferences (0.0.1): - - Flutter - -DEPENDENCIES: - - Flutter (from `Flutter`) - - key_value_store_flutter (from `.symlinks/plugins/key_value_store_flutter/ios`) - - path_provider (from `.symlinks/plugins/path_provider/ios`) - - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - -EXTERNAL SOURCES: - Flutter: - :path: Flutter - key_value_store_flutter: - :path: ".symlinks/plugins/key_value_store_flutter/ios" - path_provider: - :path: ".symlinks/plugins/path_provider/ios" - shared_preferences: - :path: ".symlinks/plugins/shared_preferences/ios" - -SPEC CHECKSUMS: - Flutter: 0e3d915762c693b495b44d77113d4970485de6ec - key_value_store_flutter: 17757389b11f4df6461c3a63b7a996062c74b13c - path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d - shared_preferences: 1feebfa37bb57264736e16865e7ffae7fc99b523 - -PODFILE CHECKSUM: 1b66dae606f75376c5f2135a8290850eeb09ae83 - -COCOAPODS: 1.8.4 diff --git a/redux/ios/Runner.xcodeproj/project.pbxproj b/redux/ios/Runner.xcodeproj/project.pbxproj index dd0da594..be7aeefd 100644 --- a/redux/ios/Runner.xcodeproj/project.pbxproj +++ b/redux/ios/Runner.xcodeproj/project.pbxproj @@ -3,23 +3,29 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 5E7495283C2EE97EE73E9CE4 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BCA19202287B052354FC31F7 /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -27,8 +33,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -38,23 +42,19 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 480AC9B32D88555244F6D203 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 6484D0F73242762AEE945887 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - ABE7BBA1000592FA3BB3A065 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - BCA19202287B052354FC31F7 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,32 +62,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - 5E7495283C2EE97EE73E9CE4 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 60B8E1B7B3D4F8767DEAF8E2 /* Pods */ = { + 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( - ABE7BBA1000592FA3BB3A065 /* Pods-Runner.debug.xcconfig */, - 480AC9B32D88555244F6D203 /* Pods-Runner.release.xcconfig */, - 6484D0F73242762AEE945887 /* Pods-Runner.profile.xcconfig */, + 331C807B294A618700263BE5 /* RunnerTests.swift */, ); - name = Pods; - path = Pods; + path = RunnerTests; sourceTree = ""; }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -101,8 +93,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - 60B8E1B7B3D4F8767DEAF8E2 /* Pods */, - B5449BEF13D944A9F24ACD12 /* Frameworks */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -110,6 +101,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -121,7 +113,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -130,36 +121,36 @@ path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; - B5449BEF13D944A9F24ACD12 /* Frameworks */ = { - isa = PBXGroup; - children = ( - BCA19202287B052354FC31F7 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 4FEA805F7E8C9CABE6EB44C4 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 20E57DA7F7B71919905952FF /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -176,9 +167,14 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -186,7 +182,7 @@ }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -199,11 +195,19 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -218,59 +222,25 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 20E57DA7F7B71919905952FF /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 4FEA805F7E8C9CABE6EB44C4 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -286,6 +256,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -297,6 +275,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -319,9 +305,9 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -351,6 +337,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -359,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -375,18 +362,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.redux; + PRODUCT_BUNDLE_IDENTIFIER = com.example.reduxSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -394,11 +377,58 @@ }; name = Profile; }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.reduxSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.reduxSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.reduxSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -428,6 +458,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -442,7 +473,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -452,9 +483,9 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -484,6 +515,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -492,11 +524,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -509,18 +542,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.redux; + PRODUCT_BUNDLE_IDENTIFIER = com.example.reduxSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -536,18 +565,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.redux; + PRODUCT_BUNDLE_IDENTIFIER = com.example.reduxSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -558,6 +583,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/redux/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/redux/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/redux/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/redux/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/redux/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/redux/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/redux/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/redux/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/redux/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/redux/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/redux/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/redux/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..e3773d42 100644 --- a/redux/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/redux/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + + + + + @@ -61,8 +73,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - - - diff --git a/redux/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/redux/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/redux/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/redux/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/redux/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/redux/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/redux/ios/Runner/AppDelegate.swift b/redux/ios/Runner/AppDelegate.swift index 70693e4a..62666446 100644 --- a/redux/ios/Runner/AppDelegate.swift +++ b/redux/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ -import UIKit import Flutter +import UIKit -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d22f10b2..d36b1fab 100644 --- a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -107,6 +107,12 @@ "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" } ], "info" : { diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 980e5ad6..7353c41e 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index fd870289..797d452e 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 75e84cd1..6ed2d933 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 03ab8a84..4cd7b009 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index a03431cb..fe730945 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index f47613ee..321773cd 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 7f2230a9..797d452e 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 42315c6d..502f463a 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index f9882cc0..0ec30343 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 45537513..0ec30343 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 6360ea17..e9f5fea2 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 152d5e12..84ac32ae 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 310b0b8f..8953cba0 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 092b7bfe..0467bf12 100644 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/redux/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/redux/ios/Runner/Info.plist b/redux/ios/Runner/Info.plist index 9f78a477..880e62e1 100644 --- a/redux/ios/Runner/Info.plist +++ b/redux/ios/Runner/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Redux Sample CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -11,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - redux + redux_sample CFBundlePackageType APPL CFBundleShortVersionString @@ -39,7 +41,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/redux/ios/Runner/Runner-Bridging-Header.h b/redux/ios/Runner/Runner-Bridging-Header.h index 7335fdf9..308a2a56 100644 --- a/redux/ios/Runner/Runner-Bridging-Header.h +++ b/redux/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file +#import "GeneratedPluginRegistrant.h" diff --git a/redux/ios/RunnerTests/RunnerTests.swift b/redux/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/redux/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/redux/lib/actions/actions.dart b/redux/lib/actions/actions.dart index b2161ec6..1b8b0efa 100644 --- a/redux/lib/actions/actions.dart +++ b/redux/lib/actions/actions.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:redux_sample/models/models.dart'; class ClearCompletedAction {} diff --git a/redux/lib/app.dart b/redux/lib/app.dart index 92dc824d..8bb4ae9e 100644 --- a/redux/lib/app.dart +++ b/redux/lib/app.dart @@ -11,7 +11,7 @@ import 'package:todos_app_core/todos_app_core.dart'; class ReduxApp extends StatelessWidget { final Store store; - const ReduxApp({Key key, this.store}) : super(key: key); + const ReduxApp({super.key, required this.store}); @override Widget build(BuildContext context) { @@ -19,7 +19,8 @@ class ReduxApp extends StatelessWidget { store: store, child: MaterialApp( onGenerateTitle: (context) => ReduxLocalizations.of(context).appTitle, - theme: ArchSampleTheme.theme, + theme: ArchSampleTheme.lightTheme, + darkTheme: ArchSampleTheme.darkTheme, localizationsDelegates: [ ArchSampleLocalizationsDelegate(), ReduxLocalizationsDelegate(), @@ -32,9 +33,7 @@ class ReduxApp extends StatelessWidget { }, ); }, - ArchSampleRoutes.addTodo: (context) { - return AddTodo(); - }, + ArchSampleRoutes.addTodo: (context) => AddTodo(), }, ), ); diff --git a/redux/lib/containers/active_tab.dart b/redux/lib/containers/active_tab.dart index 2a41419e..ffbcbcf2 100644 --- a/redux/lib/containers/active_tab.dart +++ b/redux/lib/containers/active_tab.dart @@ -1,9 +1,4 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; import 'package:redux_sample/models/models.dart'; @@ -11,7 +6,7 @@ import 'package:redux_sample/models/models.dart'; class ActiveTab extends StatelessWidget { final ViewModelBuilder builder; - ActiveTab({Key key, @required this.builder}) : super(key: key); + const ActiveTab({super.key, required this.builder}); @override Widget build(BuildContext context) { diff --git a/redux/lib/containers/add_todo.dart b/redux/lib/containers/add_todo.dart index ce53a7d8..248fc9f0 100644 --- a/redux/lib/containers/add_todo.dart +++ b/redux/lib/containers/add_todo.dart @@ -1,27 +1,20 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; import 'package:redux_sample/actions/actions.dart'; import 'package:redux_sample/models/models.dart'; import 'package:redux_sample/presentation/add_edit_screen.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class AddTodo extends StatelessWidget { - AddTodo({Key key}) : super(key: key); + const AddTodo({super.key}); @override Widget build(BuildContext context) { return StoreConnector( converter: (Store store) { return (task, note) { - store.dispatch(AddTodoAction(Todo( - task, - note: note, - ))); + store.dispatch(AddTodoAction(Todo(task, note: note))); }; }, builder: (BuildContext context, OnSaveCallback onSave) { diff --git a/redux/lib/containers/app_loading.dart b/redux/lib/containers/app_loading.dart index ed6889ac..8d769cf9 100644 --- a/redux/lib/containers/app_loading.dart +++ b/redux/lib/containers/app_loading.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; @@ -10,9 +5,9 @@ import 'package:redux_sample/models/models.dart'; import 'package:redux_sample/selectors/selectors.dart'; class AppLoading extends StatelessWidget { - final Function(BuildContext context, bool isLoading) builder; + final ViewModelBuilder builder; - AppLoading({Key key, @required this.builder}) : super(key: key); + const AppLoading({super.key, required this.builder}); @override Widget build(BuildContext context) { diff --git a/redux/lib/containers/edit_todo.dart b/redux/lib/containers/edit_todo.dart index b47ce68a..014e1c38 100644 --- a/redux/lib/containers/edit_todo.dart +++ b/redux/lib/containers/edit_todo.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/widgets.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'package:flutter_redux/flutter_redux.dart'; @@ -13,20 +9,16 @@ import 'package:redux_sample/presentation/add_edit_screen.dart'; class EditTodo extends StatelessWidget { final Todo todo; - EditTodo({this.todo, Key key}) : super(key: key); + const EditTodo({super.key, required this.todo}); @override Widget build(BuildContext context) { return StoreConnector( converter: (Store store) { return (task, note) { - store.dispatch(UpdateTodoAction( - todo.id, - todo.copyWith( - task: task, - note: note, - ), - )); + store.dispatch( + UpdateTodoAction(todo.id, todo.copyWith(task: task, note: note)), + ); }; }, builder: (BuildContext context, OnSaveCallback onSave) { diff --git a/redux/lib/containers/extra_actions_container.dart b/redux/lib/containers/extra_actions_container.dart index 9f47b18a..c754e33f 100644 --- a/redux/lib/containers/extra_actions_container.dart +++ b/redux/lib/containers/extra_actions_container.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; @@ -12,7 +7,7 @@ import 'package:redux_sample/presentation/extra_actions_button.dart'; import 'package:redux_sample/selectors/selectors.dart'; class ExtraActionsContainer extends StatelessWidget { - ExtraActionsContainer({Key key}) : super(key: key); + const ExtraActionsContainer({super.key}); @override Widget build(BuildContext context) { @@ -30,13 +25,10 @@ class ExtraActionsContainer extends StatelessWidget { } class _ViewModel { - final Function(ExtraAction) onActionSelected; + final void Function(ExtraAction) onActionSelected; final bool allComplete; - _ViewModel({ - @required this.onActionSelected, - @required this.allComplete, - }); + _ViewModel({required this.onActionSelected, required this.allComplete}); static _ViewModel fromStore(Store store) { return _ViewModel( diff --git a/redux/lib/containers/filter_selector.dart b/redux/lib/containers/filter_selector.dart index c93eafab..94b520e3 100644 --- a/redux/lib/containers/filter_selector.dart +++ b/redux/lib/containers/filter_selector.dart @@ -1,9 +1,4 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; import 'package:redux_sample/actions/actions.dart'; @@ -13,7 +8,7 @@ import 'package:redux_sample/presentation/filter_button.dart'; class FilterSelector extends StatelessWidget { final bool visible; - FilterSelector({Key key, @required this.visible}) : super(key: key); + const FilterSelector({super.key, required this.visible}); @override Widget build(BuildContext context) { @@ -32,13 +27,10 @@ class FilterSelector extends StatelessWidget { } class _ViewModel { - final Function(VisibilityFilter) onFilterSelected; + final void Function(VisibilityFilter) onFilterSelected; final VisibilityFilter activeFilter; - _ViewModel({ - @required this.onFilterSelected, - @required this.activeFilter, - }); + _ViewModel({required this.onFilterSelected, required this.activeFilter}); static _ViewModel fromStore(Store store) { return _ViewModel( diff --git a/redux/lib/containers/filtered_todos.dart b/redux/lib/containers/filtered_todos.dart index 5c5baf1e..bc3e4805 100644 --- a/redux/lib/containers/filtered_todos.dart +++ b/redux/lib/containers/filtered_todos.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; @@ -12,7 +7,7 @@ import 'package:redux_sample/presentation/todo_list.dart'; import 'package:redux_sample/selectors/selectors.dart'; class FilteredTodos extends StatelessWidget { - FilteredTodos({Key key}) : super(key: key); + const FilteredTodos({super.key}); @override Widget build(BuildContext context) { @@ -33,16 +28,16 @@ class FilteredTodos extends StatelessWidget { class _ViewModel { final List todos; final bool loading; - final Function(Todo, bool) onCheckboxChanged; - final Function(Todo) onRemove; - final Function(Todo) onUndoRemove; + final void Function(Todo, bool?) onCheckboxChanged; + final void Function(Todo) onRemove; + final void Function(Todo) onUndoRemove; _ViewModel({ - @required this.todos, - @required this.loading, - @required this.onCheckboxChanged, - @required this.onRemove, - @required this.onUndoRemove, + required this.todos, + required this.loading, + required this.onCheckboxChanged, + required this.onRemove, + required this.onUndoRemove, }); static _ViewModel fromStore(Store store) { @@ -53,10 +48,9 @@ class _ViewModel { ), loading: store.state.isLoading, onCheckboxChanged: (todo, complete) { - store.dispatch(UpdateTodoAction( - todo.id, - todo.copyWith(complete: !todo.complete), - )); + store.dispatch( + UpdateTodoAction(todo.id, todo.copyWith(complete: !todo.complete)), + ); }, onRemove: (todo) { store.dispatch(DeleteTodoAction(todo.id)); diff --git a/redux/lib/containers/stats.dart b/redux/lib/containers/stats.dart index ec12c753..04cdf8bd 100644 --- a/redux/lib/containers/stats.dart +++ b/redux/lib/containers/stats.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; @@ -11,7 +6,7 @@ import 'package:redux_sample/presentation/stats_counter.dart'; import 'package:redux_sample/selectors/selectors.dart'; class Stats extends StatelessWidget { - Stats({Key key}) : super(key: key); + const Stats({super.key}); @override Widget build(BuildContext context) { @@ -32,7 +27,7 @@ class _ViewModel { final int numCompleted; final int numActive; - _ViewModel({@required this.numCompleted, @required this.numActive}); + _ViewModel({required this.numCompleted, required this.numActive}); static _ViewModel fromStore(Store store) { return _ViewModel( diff --git a/redux/lib/containers/tab_selector.dart b/redux/lib/containers/tab_selector.dart index d3feffb1..0c56a69d 100644 --- a/redux/lib/containers/tab_selector.dart +++ b/redux/lib/containers/tab_selector.dart @@ -1,18 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; import 'package:redux_sample/actions/actions.dart'; import 'package:redux_sample/models/models.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class TabSelector extends StatelessWidget { - TabSelector({Key key}) : super(key: key); + const TabSelector({super.key}); @override Widget build(BuildContext context) { @@ -32,9 +26,9 @@ class TabSelector extends StatelessWidget { ? ArchSampleKeys.todoTab : ArchSampleKeys.statsTab, ), - title: Text(tab == AppTab.stats + label: tab == AppTab.stats ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos), + : ArchSampleLocalizations.of(context).todos, ); }).toList(), ); @@ -45,12 +39,9 @@ class TabSelector extends StatelessWidget { class _ViewModel { final AppTab activeTab; - final Function(int) onTabSelected; + final void Function(int) onTabSelected; - _ViewModel({ - @required this.activeTab, - @required this.onTabSelected, - }); + _ViewModel({required this.activeTab, required this.onTabSelected}); static _ViewModel fromStore(Store store) { return _ViewModel( diff --git a/redux/lib/containers/todo_details.dart b/redux/lib/containers/todo_details.dart index 9804cb9f..2cd4ab82 100644 --- a/redux/lib/containers/todo_details.dart +++ b/redux/lib/containers/todo_details.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; @@ -14,7 +9,7 @@ import 'package:redux_sample/selectors/selectors.dart'; class TodoDetails extends StatelessWidget { final String id; - TodoDetails({Key key, @required this.id}) : super(key: key); + const TodoDetails({super.key, required this.id}); @override Widget build(BuildContext context) { @@ -36,13 +31,13 @@ class TodoDetails extends StatelessWidget { class _ViewModel { final Todo todo; - final Function onDelete; - final Function(bool) toggleCompleted; + final void Function() onDelete; + final void Function(bool?) toggleCompleted; _ViewModel({ - @required this.todo, - @required this.onDelete, - @required this.toggleCompleted, + required this.todo, + required this.onDelete, + required this.toggleCompleted, }); factory _ViewModel.from(Store store, String id) { @@ -52,10 +47,9 @@ class _ViewModel { todo: todo, onDelete: () => store.dispatch(DeleteTodoAction(todo.id)), toggleCompleted: (isComplete) { - store.dispatch(UpdateTodoAction( - todo.id, - todo.copyWith(complete: isComplete), - )); + store.dispatch( + UpdateTodoAction(todo.id, todo.copyWith(complete: isComplete)), + ); }, ); } diff --git a/redux/lib/localization.dart b/redux/lib/localization.dart index e0335b55..38ba4ddc 100644 --- a/redux/lib/localization.dart +++ b/redux/lib/localization.dart @@ -1,17 +1,10 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; class ReduxLocalizations { static ReduxLocalizations of(BuildContext context) { - return Localizations.of( - context, - ReduxLocalizations, - ); + return Localizations.of(context, ReduxLocalizations)!; } String get appTitle => 'Redux Example'; diff --git a/redux/lib/main.dart b/redux/lib/main.dart index 71e9857c..77b65054 100644 --- a/redux/lib/main.dart +++ b/redux/lib/main.dart @@ -1,9 +1,4 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:key_value_store_flutter/key_value_store_flutter.dart'; import 'package:redux/redux.dart'; import 'package:redux_sample/app.dart'; import 'package:redux_sample/reducers/app_state_reducer.dart'; @@ -16,16 +11,20 @@ import 'models/app_state.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(ReduxApp( - store: Store( - appReducer, - initialState: AppState.loading(), - middleware: createStoreTodosMiddleware(LocalStorageRepository( - localStorage: KeyValueStorage( - 'redux', - FlutterKeyValueStore(await SharedPreferences.getInstance()), + runApp( + ReduxApp( + store: Store( + appReducer, + initialState: AppState.loading(), + middleware: createStoreTodosMiddleware( + LocalStorageRepository( + localStorage: KeyValueStorage( + 'redux', + await SharedPreferences.getInstance(), + ), + ), ), - )), + ), ), - )); + ); } diff --git a/redux/lib/main_web.dart b/redux/lib/main_web.dart deleted file mode 100644 index ed0f9a4b..00000000 --- a/redux/lib/main_web.dart +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:html'; - -import 'package:flutter/material.dart'; -import 'package:key_value_store_web/key_value_store_web.dart'; -import 'package:redux/redux.dart'; -import 'package:redux_sample/app.dart'; -import 'package:redux_sample/middleware/store_todos_middleware.dart'; -import 'package:redux_sample/models/app_state.dart'; -import 'package:redux_sample/reducers/app_state_reducer.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(ReduxApp( - store: Store( - appReducer, - initialState: AppState.loading(), - middleware: createStoreTodosMiddleware(LocalStorageRepository( - localStorage: KeyValueStorage( - 'redux', - WebKeyValueStore(window.localStorage), - ), - )), - ), - )); -} diff --git a/redux/lib/middleware/store_todos_middleware.dart b/redux/lib/middleware/store_todos_middleware.dart index 1b24e12f..af0feac0 100644 --- a/redux/lib/middleware/store_todos_middleware.dart +++ b/redux/lib/middleware/store_todos_middleware.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:redux/redux.dart'; import 'package:redux_sample/actions/actions.dart'; import 'package:redux_sample/models/models.dart'; @@ -15,13 +11,13 @@ List> createStoreTodosMiddleware( final loadTodos = _createLoadTodos(repository); return [ - TypedMiddleware(loadTodos), - TypedMiddleware(saveTodos), - TypedMiddleware(saveTodos), - TypedMiddleware(saveTodos), - TypedMiddleware(saveTodos), - TypedMiddleware(saveTodos), - TypedMiddleware(saveTodos), + TypedMiddleware(loadTodos).call, + TypedMiddleware(saveTodos).call, + TypedMiddleware(saveTodos).call, + TypedMiddleware(saveTodos).call, + TypedMiddleware(saveTodos).call, + TypedMiddleware(saveTodos).call, + TypedMiddleware(saveTodos).call, ]; } @@ -37,15 +33,16 @@ Middleware _createSaveTodos(TodosRepository repository) { Middleware _createLoadTodos(TodosRepository repository) { return (Store store, action, NextDispatcher next) { - repository.loadTodos().then( - (todos) { - store.dispatch( - TodosLoadedAction( - todos.map(Todo.fromEntity).toList(), - ), - ); - }, - ).catchError((_) => store.dispatch(TodosNotLoadedAction())); + repository + .loadTodos() + .then((todos) { + store.dispatch( + TodosLoadedAction(todos.map(Todo.fromEntity).toList()), + ); + }) + .catchError((_) { + store.dispatch(TodosNotLoadedAction()); + }); next(action); }; diff --git a/redux/lib/models/app_state.dart b/redux/lib/models/app_state.dart index 8374d226..cea509d9 100644 --- a/redux/lib/models/app_state.dart +++ b/redux/lib/models/app_state.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:meta/meta.dart'; import 'package:redux_sample/models/models.dart'; @@ -12,19 +8,20 @@ class AppState { final AppTab activeTab; final VisibilityFilter activeFilter; - AppState( - {this.isLoading = false, - this.todos = const [], - this.activeTab = AppTab.todos, - this.activeFilter = VisibilityFilter.all}); + const AppState({ + this.isLoading = false, + this.todos = const [], + this.activeTab = AppTab.todos, + this.activeFilter = VisibilityFilter.all, + }); factory AppState.loading() => AppState(isLoading: true); AppState copyWith({ - bool isLoading, - List todos, - AppTab activeTab, - VisibilityFilter activeFilter, + bool? isLoading, + List? todos, + AppTab? activeTab, + VisibilityFilter? activeFilter, }) { return AppState( isLoading: isLoading ?? this.isLoading, diff --git a/redux/lib/models/app_tab.dart b/redux/lib/models/app_tab.dart index 096b6f56..8348dfcf 100644 --- a/redux/lib/models/app_tab.dart +++ b/redux/lib/models/app_tab.dart @@ -1,5 +1 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - enum AppTab { todos, stats } diff --git a/redux/lib/models/extra_action.dart b/redux/lib/models/extra_action.dart index 236a7d0b..4ca0c02b 100644 --- a/redux/lib/models/extra_action.dart +++ b/redux/lib/models/extra_action.dart @@ -1,5 +1 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - enum ExtraAction { toggleAllComplete, clearCompleted } diff --git a/redux/lib/models/models.dart b/redux/lib/models/models.dart index 6951f5b7..e2e948c9 100644 --- a/redux/lib/models/models.dart +++ b/redux/lib/models/models.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - export 'app_state.dart'; export 'app_tab.dart'; export 'extra_action.dart'; diff --git a/redux/lib/models/todo.dart b/redux/lib/models/todo.dart index 025120dc..ccdf3cbd 100644 --- a/redux/lib/models/todo.dart +++ b/redux/lib/models/todo.dart @@ -1,9 +1,5 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:todos_app_core/todos_app_core.dart'; import 'package:meta/meta.dart'; +import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @immutable @@ -13,11 +9,10 @@ class Todo { final String note; final String task; - Todo(this.task, {this.complete = false, String note = '', String id}) - : note = note ?? '', - id = id ?? Uuid().generateV4(); + Todo(this.task, {this.complete = false, this.note = '', String? id}) + : id = id ?? Uuid().generateV4(); - Todo copyWith({bool complete, String id, String note, String task}) { + Todo copyWith({bool? complete, String? id, String? note, String? task}) { return Todo( task ?? this.task, complete: complete ?? this.complete, @@ -52,9 +47,9 @@ class Todo { static Todo fromEntity(TodoEntity entity) { return Todo( entity.task, - complete: entity.complete ?? false, + complete: entity.complete, note: entity.note, - id: entity.id ?? Uuid().generateV4(), + id: entity.id, ); } } diff --git a/redux/lib/models/visibility_filter.dart b/redux/lib/models/visibility_filter.dart index 11f11982..a47beca1 100644 --- a/redux/lib/models/visibility_filter.dart +++ b/redux/lib/models/visibility_filter.dart @@ -1,5 +1 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - enum VisibilityFilter { all, active, completed } diff --git a/redux/lib/presentation/add_edit_screen.dart b/redux/lib/presentation/add_edit_screen.dart index a53fd98b..1e7a4540 100644 --- a/redux/lib/presentation/add_edit_screen.dart +++ b/redux/lib/presentation/add_edit_screen.dart @@ -1,31 +1,30 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:redux_sample/models/models.dart'; +import 'package:todos_app_core/todos_app_core.dart'; typedef OnSaveCallback = void Function(String task, String note); class AddEditScreen extends StatefulWidget { final bool isEditing; final OnSaveCallback onSave; - final Todo todo; + final Todo? todo; + + const AddEditScreen({ + super.key = ArchSampleKeys.addTodoScreen, + required this.onSave, + required this.isEditing, + this.todo, + }); - AddEditScreen( - {Key key, @required this.onSave, @required this.isEditing, this.todo}) - : super(key: key ?? ArchSampleKeys.addTodoScreen); @override - _AddEditScreenState createState() => _AddEditScreenState(); + AddEditScreenState createState() => AddEditScreenState(); } -class _AddEditScreenState extends State { +class AddEditScreenState extends State { static final GlobalKey _formKey = GlobalKey(); - String _task; - String _note; + late String _task; + late String _note; bool get isEditing => widget.isEditing; @@ -36,9 +35,7 @@ class _AddEditScreenState extends State { return Scaffold( appBar: AppBar( - title: Text( - isEditing ? localizations.editTodo : localizations.addTodo, - ), + title: Text(isEditing ? localizations.editTodo : localizations.addTodo), ), body: Padding( padding: EdgeInsets.all(16.0), @@ -47,42 +44,41 @@ class _AddEditScreenState extends State { child: ListView( children: [ TextFormField( - initialValue: isEditing ? widget.todo.task : '', + initialValue: isEditing ? widget.todo!.task : '', key: ArchSampleKeys.taskField, autofocus: !isEditing, - style: textTheme.headline, + style: textTheme.titleLarge, decoration: InputDecoration( hintText: localizations.newTodoHint, ), validator: (val) { - return val.trim().isEmpty + return val != null && val.trim().isEmpty ? localizations.emptyTodoError : null; }, - onSaved: (value) => _task = value, + onSaved: (value) => _task = value ?? '', ), TextFormField( - initialValue: isEditing ? widget.todo.note : '', + initialValue: isEditing ? widget.todo!.note : '', key: ArchSampleKeys.noteField, maxLines: 10, - style: textTheme.subhead, - decoration: InputDecoration( - hintText: localizations.notesHint, - ), - onSaved: (value) => _note = value, - ) + style: textTheme.titleMedium, + decoration: InputDecoration(hintText: localizations.notesHint), + onSaved: (value) => _note = value ?? '', + ), ], ), ), ), floatingActionButton: FloatingActionButton( - key: - isEditing ? ArchSampleKeys.saveTodoFab : ArchSampleKeys.saveNewTodo, + key: isEditing + ? ArchSampleKeys.saveTodoFab + : ArchSampleKeys.saveNewTodo, tooltip: isEditing ? localizations.saveChanges : localizations.addTodo, child: Icon(isEditing ? Icons.check : Icons.add), onPressed: () { - if (_formKey.currentState.validate()) { - _formKey.currentState.save(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); widget.onSave(_task, _note); Navigator.pop(context); diff --git a/redux/lib/presentation/details_screen.dart b/redux/lib/presentation/details_screen.dart index 34162960..57f36584 100644 --- a/redux/lib/presentation/details_screen.dart +++ b/redux/lib/presentation/details_screen.dart @@ -1,24 +1,19 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:redux_sample/containers/edit_todo.dart'; import 'package:redux_sample/models/models.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class DetailsScreen extends StatelessWidget { final Todo todo; - final Function onDelete; - final Function(bool) toggleCompleted; + final void Function() onDelete; + final void Function(bool?) toggleCompleted; - DetailsScreen({ - Key key, - @required this.todo, - @required this.onDelete, - @required this.toggleCompleted, - }) : super(key: key ?? ArchSampleKeys.todoDetailsScreen); + const DetailsScreen({ + super.key = ArchSampleKeys.todoDetailsScreen, + required this.todo, + required this.onDelete, + required this.toggleCompleted, + }); @override Widget build(BuildContext context) { @@ -36,7 +31,7 @@ class DetailsScreen extends StatelessWidget { onDelete(); Navigator.pop(context, todo); }, - ) + ), ], ), body: Padding( @@ -61,21 +56,18 @@ class DetailsScreen extends StatelessWidget { tag: '${todo.id}__heroTag', child: Container( width: MediaQuery.of(context).size.width, - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), + padding: EdgeInsets.only(top: 8.0, bottom: 16.0), child: Text( todo.task, key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, ), ), ), Text( todo.note, key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ], ), @@ -90,12 +82,10 @@ class DetailsScreen extends StatelessWidget { tooltip: localizations.editTodo, child: Icon(Icons.edit), onPressed: () { - Navigator.of(context).push( + Navigator.of(context).push( MaterialPageRoute( builder: (context) { - return EditTodo( - todo: todo, - ); + return EditTodo(todo: todo); }, ), ); diff --git a/redux/lib/presentation/extra_actions_button.dart b/redux/lib/presentation/extra_actions_button.dart index 5170a554..1c0cf329 100644 --- a/redux/lib/presentation/extra_actions_button.dart +++ b/redux/lib/presentation/extra_actions_button.dart @@ -1,20 +1,16 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:redux_sample/models/models.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class ExtraActionsButton extends StatelessWidget { final PopupMenuItemSelected onSelected; final bool allComplete; - ExtraActionsButton({ - this.onSelected, + const ExtraActionsButton({ + super.key = ArchSampleKeys.extraActionsButton, + required this.onSelected, this.allComplete = false, - Key key, - }) : super(key: ArchSampleKeys.extraActionsButton); + }); @override Widget build(BuildContext context) { @@ -24,9 +20,11 @@ class ExtraActionsButton extends StatelessWidget { PopupMenuItem( key: ArchSampleKeys.toggleAll, value: ExtraAction.toggleAllComplete, - child: Text(allComplete - ? ArchSampleLocalizations.of(context).markAllIncomplete - : ArchSampleLocalizations.of(context).markAllComplete), + child: Text( + allComplete + ? ArchSampleLocalizations.of(context).markAllIncomplete + : ArchSampleLocalizations.of(context).markAllComplete, + ), ), PopupMenuItem( key: ArchSampleKeys.clearCompleted, diff --git a/redux/lib/presentation/filter_button.dart b/redux/lib/presentation/filter_button.dart index 03345913..0c37f8f4 100644 --- a/redux/lib/presentation/filter_button.dart +++ b/redux/lib/presentation/filter_button.dart @@ -1,26 +1,26 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:redux_sample/models/models.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class FilterButton extends StatelessWidget { final PopupMenuItemSelected onSelected; final VisibilityFilter activeFilter; final bool visible; - FilterButton({this.onSelected, this.activeFilter, this.visible, Key key}) - : super(key: key); + const FilterButton({ + super.key, + required this.onSelected, + required this.activeFilter, + required this.visible, + }); @override Widget build(BuildContext context) { - final defaultStyle = Theme.of(context).textTheme.body1; - final activeStyle = Theme.of(context) - .textTheme - .body1 - .copyWith(color: Theme.of(context).accentColor); + final defaultStyle = Theme.of(context).textTheme.bodyMedium!; + final activeStyle = defaultStyle.copyWith( + color: Theme.of(context).colorScheme.secondary, + ); + final button = _Button( onSelected: onSelected, activeFilter: activeFilter, @@ -38,12 +38,11 @@ class FilterButton extends StatelessWidget { class _Button extends StatelessWidget { const _Button({ - Key key, - @required this.onSelected, - @required this.activeFilter, - @required this.activeStyle, - @required this.defaultStyle, - }) : super(key: key); + required this.onSelected, + required this.activeFilter, + required this.activeStyle, + required this.defaultStyle, + }); final PopupMenuItemSelected onSelected; final VisibilityFilter activeFilter; diff --git a/redux/lib/presentation/home_screen.dart b/redux/lib/presentation/home_screen.dart index 22f8db27..2af4a899 100644 --- a/redux/lib/presentation/home_screen.dart +++ b/redux/lib/presentation/home_screen.dart @@ -1,9 +1,4 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:redux_sample/containers/active_tab.dart'; import 'package:redux_sample/containers/extra_actions_container.dart'; import 'package:redux_sample/containers/filter_selector.dart'; @@ -12,11 +7,15 @@ import 'package:redux_sample/containers/stats.dart'; import 'package:redux_sample/containers/tab_selector.dart'; import 'package:redux_sample/localization.dart'; import 'package:redux_sample/models/models.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class HomeScreen extends StatefulWidget { final void Function() onInit; - HomeScreen({@required this.onInit}) : super(key: ArchSampleKeys.homeScreen); + const HomeScreen({ + super.key = ArchSampleKeys.homeScreen, + required this.onInit, + }); @override HomeScreenState createState() => HomeScreenState(); @@ -47,8 +46,8 @@ class HomeScreenState extends State { onPressed: () { Navigator.pushNamed(context, ArchSampleRoutes.addTodo); }, - child: Icon(Icons.add), tooltip: ArchSampleLocalizations.of(context).addTodo, + child: Icon(Icons.add), ), bottomNavigationBar: TabSelector(), ); diff --git a/redux/lib/presentation/loading_indicator.dart b/redux/lib/presentation/loading_indicator.dart index 822a4c32..9d9fea74 100644 --- a/redux/lib/presentation/loading_indicator.dart +++ b/redux/lib/presentation/loading_indicator.dart @@ -1,16 +1,11 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class LoadingIndicator extends StatelessWidget { - LoadingIndicator({Key key}) : super(key: key); + const LoadingIndicator({super.key = ArchSampleKeys.todosLoading}); @override Widget build(BuildContext context) { - return Center( - child: CircularProgressIndicator(), - ); + return Center(child: CircularProgressIndicator()); } } diff --git a/redux/lib/presentation/stats_counter.dart b/redux/lib/presentation/stats_counter.dart index 55fe82e5..9a37df94 100644 --- a/redux/lib/presentation/stats_counter.dart +++ b/redux/lib/presentation/stats_counter.dart @@ -1,30 +1,27 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:redux_sample/containers/app_loading.dart'; import 'package:redux_sample/presentation/loading_indicator.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class StatsCounter extends StatelessWidget { final int numActive; final int numCompleted; - StatsCounter({ - @required this.numActive, - @required this.numCompleted, + const StatsCounter({ + super.key, + required this.numActive, + required this.numCompleted, }); @override Widget build(BuildContext context) { - return AppLoading(builder: (context, loading) { - return loading - ? LoadingIndicator(key: Key('__statsLoading__')) - : _buildStats(context); - }); + return AppLoading( + builder: (context, loading) { + return loading + ? LoadingIndicator(key: Key('__statsLoading__')) + : _buildStats(context); + }, + ); } Widget _buildStats(BuildContext context) { @@ -36,7 +33,7 @@ class StatsCounter extends StatelessWidget { padding: EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -44,14 +41,14 @@ class StatsCounter extends StatelessWidget { child: Text( '$numCompleted', key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), Padding( padding: EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -59,9 +56,9 @@ class StatsCounter extends StatelessWidget { child: Text( '$numActive', key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), - ) + ), ], ), ); diff --git a/redux/lib/presentation/todo_item.dart b/redux/lib/presentation/todo_item.dart index b8d16386..23863554 100644 --- a/redux/lib/presentation/todo_item.dart +++ b/redux/lib/presentation/todo_item.dart @@ -1,23 +1,19 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:redux_sample/models/models.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class TodoItem extends StatelessWidget { final DismissDirectionCallback onDismissed; final GestureTapCallback onTap; - final ValueChanged onCheckboxChanged; + final ValueChanged onCheckboxChanged; final Todo todo; - TodoItem({ - @required this.onDismissed, - @required this.onTap, - @required this.onCheckboxChanged, - @required this.todo, + const TodoItem({ + super.key, + required this.onDismissed, + required this.onTap, + required this.onCheckboxChanged, + required this.todo, }); @override @@ -34,12 +30,12 @@ class TodoItem extends StatelessWidget { ), title: Hero( tag: '${todo.id}__heroTag', - child: Container( + child: SizedBox( width: MediaQuery.of(context).size.width, child: Text( todo.task, key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), ), @@ -48,7 +44,7 @@ class TodoItem extends StatelessWidget { key: ArchSampleKeys.todoItemNote(todo.id), maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ); diff --git a/redux/lib/presentation/todo_list.dart b/redux/lib/presentation/todo_list.dart index 75b76fb1..4923d503 100644 --- a/redux/lib/presentation/todo_list.dart +++ b/redux/lib/presentation/todo_list.dart @@ -1,37 +1,32 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:redux_sample/containers/app_loading.dart'; import 'package:redux_sample/containers/todo_details.dart'; import 'package:redux_sample/models/models.dart'; import 'package:redux_sample/presentation/loading_indicator.dart'; import 'package:redux_sample/presentation/todo_item.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class TodoList extends StatelessWidget { final List todos; - final Function(Todo, bool) onCheckboxChanged; - final Function(Todo) onRemove; - final Function(Todo) onUndoRemove; + final void Function(Todo, bool?) onCheckboxChanged; + final void Function(Todo) onRemove; + final void Function(Todo) onUndoRemove; - TodoList({ - Key key, - @required this.todos, - @required this.onCheckboxChanged, - @required this.onRemove, - @required this.onUndoRemove, - }) : super(key: key); + const TodoList({ + super.key, + required this.todos, + required this.onCheckboxChanged, + required this.onRemove, + required this.onUndoRemove, + }); @override Widget build(BuildContext context) { - return AppLoading(builder: (context, loading) { - return loading - ? LoadingIndicator(key: ArchSampleKeys.todosLoading) - : _buildListView(); - }); + return AppLoading( + builder: (context, loading) { + return loading ? LoadingIndicator() : _buildListView(); + }, + ); } ListView _buildListView() { @@ -58,7 +53,8 @@ class TodoList extends StatelessWidget { void _removeTodo(BuildContext context, Todo todo) { onRemove(todo); - Scaffold.of(context).showSnackBar(SnackBar( + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( duration: Duration(seconds: 2), content: Text( ArchSampleLocalizations.of(context).todoDeleted(todo.task), @@ -68,31 +64,34 @@ class TodoList extends StatelessWidget { action: SnackBarAction( label: ArchSampleLocalizations.of(context).undo, onPressed: () => onUndoRemove(todo), - ))); + ), + ), + ); } void _onTodoTap(BuildContext context, Todo todo) { Navigator.of(context) - .push(MaterialPageRoute( - builder: (_) => TodoDetails(id: todo.id), - )) + .push(MaterialPageRoute(builder: (_) => TodoDetails(id: todo.id))) .then((removedTodo) { - if (removedTodo != null) { - Scaffold.of(context).showSnackBar(SnackBar( - key: ArchSampleKeys.snackbar, - duration: Duration(seconds: 2), - content: Text( - ArchSampleLocalizations.of(context).todoDeleted(todo.task), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - action: SnackBarAction( - label: ArchSampleLocalizations.of(context).undo, - onPressed: () { - onUndoRemove(todo); - }, - ))); - } - }); + if (removedTodo != null && context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + key: ArchSampleKeys.snackbar, + duration: Duration(seconds: 2), + content: Text( + ArchSampleLocalizations.of(context).todoDeleted(todo.task), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + action: SnackBarAction( + label: ArchSampleLocalizations.of(context).undo, + onPressed: () { + onUndoRemove(todo); + }, + ), + ), + ); + } + }); } } diff --git a/redux/lib/presentation/typedefs.dart b/redux/lib/presentation/typedefs.dart index ace7d67f..95c20281 100644 --- a/redux/lib/presentation/typedefs.dart +++ b/redux/lib/presentation/typedefs.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:redux_sample/models/models.dart'; typedef TodoAdder = void Function(Todo todo); diff --git a/redux/lib/reducers/app_state_reducer.dart b/redux/lib/reducers/app_state_reducer.dart index d02e7347..b9f292af 100644 --- a/redux/lib/reducers/app_state_reducer.dart +++ b/redux/lib/reducers/app_state_reducer.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:redux_sample/models/models.dart'; import 'package:redux_sample/reducers/loading_reducer.dart'; import 'package:redux_sample/reducers/tabs_reducer.dart'; @@ -9,7 +5,7 @@ import 'package:redux_sample/reducers/todos_reducer.dart'; import 'package:redux_sample/reducers/visibility_reducer.dart'; // We create the State reducer by combining many smaller reducers into one! -AppState appReducer(AppState state, action) { +AppState appReducer(AppState state, dynamic action) { return AppState( isLoading: loadingReducer(state.isLoading, action), todos: todosReducer(state.todos, action), diff --git a/redux/lib/reducers/loading_reducer.dart b/redux/lib/reducers/loading_reducer.dart index 10659117..06227102 100644 --- a/redux/lib/reducers/loading_reducer.dart +++ b/redux/lib/reducers/loading_reducer.dart @@ -1,15 +1,11 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:redux/redux.dart'; import 'package:redux_sample/actions/actions.dart'; final loadingReducer = combineReducers([ - TypedReducer(_setLoaded), - TypedReducer(_setLoaded), + TypedReducer(_setLoaded).call, + TypedReducer(_setLoaded).call, ]); -bool _setLoaded(bool state, action) { +bool _setLoaded(bool state, dynamic action) { return false; } diff --git a/redux/lib/reducers/tabs_reducer.dart b/redux/lib/reducers/tabs_reducer.dart index 19a61051..d667ecfe 100644 --- a/redux/lib/reducers/tabs_reducer.dart +++ b/redux/lib/reducers/tabs_reducer.dart @@ -1,15 +1,10 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:redux/redux.dart'; import 'package:redux_sample/actions/actions.dart'; import 'package:redux_sample/models/models.dart'; final tabsReducer = combineReducers([ - TypedReducer(_activeTabReducer), + TypedReducer(_activeTabReducer).call, ]); -AppTab _activeTabReducer(AppTab activeTab, UpdateTabAction action) { - return action.newTab; -} +AppTab _activeTabReducer(AppTab activeTab, UpdateTabAction action) => + action.newTab; diff --git a/redux/lib/reducers/todos_reducer.dart b/redux/lib/reducers/todos_reducer.dart index c767e25b..feeed50d 100644 --- a/redux/lib/reducers/todos_reducer.dart +++ b/redux/lib/reducers/todos_reducer.dart @@ -1,20 +1,16 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:redux/redux.dart'; import 'package:redux_sample/actions/actions.dart'; import 'package:redux_sample/models/models.dart'; import 'package:redux_sample/selectors/selectors.dart'; final todosReducer = combineReducers>([ - TypedReducer, AddTodoAction>(_addTodo), - TypedReducer, DeleteTodoAction>(_deleteTodo), - TypedReducer, UpdateTodoAction>(_updateTodo), - TypedReducer, ClearCompletedAction>(_clearCompleted), - TypedReducer, ToggleAllAction>(_toggleAll), - TypedReducer, TodosLoadedAction>(_setLoadedTodos), - TypedReducer, TodosNotLoadedAction>(_setNoTodos), + TypedReducer, AddTodoAction>(_addTodo).call, + TypedReducer, DeleteTodoAction>(_deleteTodo).call, + TypedReducer, UpdateTodoAction>(_updateTodo).call, + TypedReducer, ClearCompletedAction>(_clearCompleted).call, + TypedReducer, ToggleAllAction>(_toggleAll).call, + TypedReducer, TodosLoadedAction>(_setLoadedTodos).call, + TypedReducer, TodosNotLoadedAction>(_setNoTodos).call, ]); List _addTodo(List todos, AddTodoAction action) { diff --git a/redux/lib/reducers/visibility_reducer.dart b/redux/lib/reducers/visibility_reducer.dart index 43853a7c..dabdb5f4 100644 --- a/redux/lib/reducers/visibility_reducer.dart +++ b/redux/lib/reducers/visibility_reducer.dart @@ -1,16 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:redux/redux.dart'; import 'package:redux_sample/actions/actions.dart'; import 'package:redux_sample/models/models.dart'; final visibilityReducer = combineReducers([ - TypedReducer(_activeFilterReducer), + TypedReducer(_activeFilterReducer).call, ]); VisibilityFilter _activeFilterReducer( - VisibilityFilter activeFilter, UpdateFilterAction action) { - return action.newFilter; -} + VisibilityFilter activeFilter, + UpdateFilterAction action, +) => action.newFilter; diff --git a/redux/lib/selectors/selectors.dart b/redux/lib/selectors/selectors.dart index b904dad7..55518f20 100644 --- a/redux/lib/selectors/selectors.dart +++ b/redux/lib/selectors/selectors.dart @@ -1,9 +1,5 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:todos_app_core/todos_app_core.dart'; import 'package:redux_sample/models/models.dart'; +import 'package:todos_app_core/todos_app_core.dart'; List todosSelector(AppState state) => state.todos; @@ -33,7 +29,6 @@ List filteredTodosSelector( case VisibilityFilter.completed: return todo.complete; case VisibilityFilter.all: - default: return true; } }).toList(); diff --git a/redux/linux/.gitignore b/redux/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/redux/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/redux/linux/CMakeLists.txt b/redux/linux/CMakeLists.txt new file mode 100644 index 00000000..778b7d24 --- /dev/null +++ b/redux/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +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 "redux_sample") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.redux_sample") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +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() + +# 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() + +# 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_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# 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 +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# 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() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +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) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/redux/linux/flutter/CMakeLists.txt b/redux/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/redux/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +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. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# 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/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter 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. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/redux/linux/flutter/generated_plugin_registrant.cc b/redux/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e71a16d2 --- /dev/null +++ b/redux/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/redux/linux/flutter/generated_plugin_registrant.h b/redux/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/redux/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/redux/linux/flutter/generated_plugins.cmake b/redux/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/redux/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + 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}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/redux/linux/runner/CMakeLists.txt b/redux/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/redux/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "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 +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/redux/linux/runner/main.cc b/redux/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/redux/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/redux/linux/runner/my_application.cc b/redux/linux/runner/my_application.cc new file mode 100644 index 00000000..567f2378 --- /dev/null +++ b/redux/linux/runner/my_application.cc @@ -0,0 +1,144 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView *view) +{ + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // 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 + // desktop). + // 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. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "redux_sample"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "redux_sample"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/redux/linux/runner/my_application.h b/redux/linux/runner/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/redux/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/redux/macos/.gitignore b/redux/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/redux/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/redux/macos/Flutter/Flutter-Debug.xcconfig b/redux/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/redux/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/redux/macos/Flutter/Flutter-Release.xcconfig b/redux/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/redux/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/redux/macos/Flutter/GeneratedPluginRegistrant.swift b/redux/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b8e2b22f --- /dev/null +++ b/redux/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/redux/macos/Podfile b/redux/macos/Podfile new file mode 100644 index 00000000..ff5ddb3b --- /dev/null +++ b/redux/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/redux/macos/Podfile.lock b/redux/macos/Podfile.lock new file mode 100644 index 00000000..d2f9a639 --- /dev/null +++ b/redux/macos/Podfile.lock @@ -0,0 +1,30 @@ +PODS: + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + +SPEC CHECKSUMS: + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.16.2 diff --git a/redux/macos/Runner.xcodeproj/project.pbxproj b/redux/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..5c1453de --- /dev/null +++ b/redux/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + A0BDCCDD9FE38594F043A2C5 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 59DA7F3F064D5DB0DA14E03A /* Pods_RunnerTests.framework */; }; + AA25D07C6F90872979FB7D7E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6966F0123F3819531B0BAA60 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* redux_sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = redux_sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 5789A6CDB481FE81A6246B2F /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 59DA7F3F064D5DB0DA14E03A /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6966F0123F3819531B0BAA60 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 82CC2E6BD01825E3FB46470C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 90E611559D867180A313A29C /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + CDEE05271C042EC7B7FD482F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + E06C0629C74FBC0EAE5BF142 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + FAC92A148E980EF9EB335838 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A0BDCCDD9FE38594F043A2C5 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AA25D07C6F90872979FB7D7E /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 3F33056A10D60697C1997FAA /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* redux_sample.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 3F33056A10D60697C1997FAA /* Pods */ = { + isa = PBXGroup; + children = ( + FAC92A148E980EF9EB335838 /* Pods-Runner.debug.xcconfig */, + E06C0629C74FBC0EAE5BF142 /* Pods-Runner.release.xcconfig */, + CDEE05271C042EC7B7FD482F /* Pods-Runner.profile.xcconfig */, + 5789A6CDB481FE81A6246B2F /* Pods-RunnerTests.debug.xcconfig */, + 82CC2E6BD01825E3FB46470C /* Pods-RunnerTests.release.xcconfig */, + 90E611559D867180A313A29C /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 6966F0123F3819531B0BAA60 /* Pods_Runner.framework */, + 59DA7F3F064D5DB0DA14E03A /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 68449A94B5081A8EA73F9946 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + C31C8F99AAE62C9EC785713A /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + FE5B6796877EB6F15E0ED952 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* redux_sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 68449A94B5081A8EA73F9946 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C31C8F99AAE62C9EC785713A /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + FE5B6796877EB6F15E0ED952 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5789A6CDB481FE81A6246B2F /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.reduxSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/redux_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/redux_sample"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 82CC2E6BD01825E3FB46470C /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.reduxSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/redux_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/redux_sample"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 90E611559D867180A313A29C /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.reduxSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/redux_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/redux_sample"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/redux/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/redux/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/redux/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/redux/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/redux/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..30749ce3 --- /dev/null +++ b/redux/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/redux/macos/Runner.xcworkspace/contents.xcworkspacedata b/redux/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/redux/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/redux/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/redux/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/redux/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/redux/macos/Runner/AppDelegate.swift b/redux/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/redux/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/redux/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/redux/macos/Runner/Base.lproj/MainMenu.xib b/redux/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/redux/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/redux/macos/Runner/Configs/AppInfo.xcconfig b/redux/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..bf20e5bd --- /dev/null +++ b/redux/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// 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 +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = redux_sample + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.reduxSample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/redux/macos/Runner/Configs/Debug.xcconfig b/redux/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/redux/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/redux/macos/Runner/Configs/Release.xcconfig b/redux/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/redux/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/redux/macos/Runner/Configs/Warnings.xcconfig b/redux/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/redux/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/redux/macos/Runner/DebugProfile.entitlements b/redux/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/redux/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/redux/macos/Runner/Info.plist b/redux/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/redux/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/redux/macos/Runner/MainFlutterWindow.swift b/redux/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/redux/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/redux/macos/Runner/Release.entitlements b/redux/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/redux/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/redux/macos/RunnerTests/RunnerTests.swift b/redux/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/redux/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/redux/pubspec.yaml b/redux/pubspec.yaml index ed270298..c9041e7f 100644 --- a/redux/pubspec.yaml +++ b/redux/pubspec.yaml @@ -12,42 +12,41 @@ description: A new Flutter project. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html version: 1.0.0+1 +publish_to: none environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ^3.9.0 dependencies: flutter: sdk: flutter - meta: '>=1.1.0 <2.0.0' - redux: ^3.0.0 - flutter_redux: ^0.5.3 + flutter_redux: + meta: + redux: + shared_preferences: todos_app_core: path: ../todos_app_core todos_repository_core: path: ../todos_repository_core todos_repository_local_storage: path: ../todos_repository_local_storage - key_value_store_flutter: - key_value_store_web: - shared_preferences: dev_dependencies: + flutter_lints: flutter_test: sdk: flutter - flutter_driver: + integration_test: sdk: flutter - test: - mockito: integration_tests: path: ../integration_tests + mockito: + test: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. diff --git a/redux/test/middleware_test.dart b/redux/test/middleware_test.dart index a5460d4e..795a4631 100644 --- a/redux/test/middleware_test.dart +++ b/redux/test/middleware_test.dart @@ -1,8 +1,5 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:redux/redux.dart'; import 'package:redux_sample/actions/actions.dart'; @@ -11,8 +8,9 @@ import 'package:redux_sample/models/models.dart'; import 'package:redux_sample/reducers/app_state_reducer.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; -class MockTodosRepository extends Mock implements TodosRepository {} +import 'middleware_test.mocks.dart'; +@GenerateNiceMocks([MockSpec()]) void main() { group('Save State Middleware', () { test('should load the todos in response to a LoadTodosAction', () { @@ -22,9 +20,7 @@ void main() { initialState: AppState.loading(), middleware: createStoreTodosMiddleware(repository), ); - final todos = [ - TodoEntity('Moin', '1', 'Note', false), - ]; + final todos = [TodoEntity('Moin', '1', 'Note', false)]; when(repository.loadTodos()).thenAnswer((_) => Future.value(todos)); diff --git a/redux/test/middleware_test.mocks.dart b/redux/test/middleware_test.mocks.dart new file mode 100644 index 00000000..af30ff36 --- /dev/null +++ b/redux/test/middleware_test.mocks.dart @@ -0,0 +1,51 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in redux_sample/test/middleware_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:todos_repository_core/src/todo_entity.dart' as _i4; +import 'package:todos_repository_core/src/todos_repository.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +/// A class which mocks [TodosRepository]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodosRepository extends _i1.Mock implements _i2.TodosRepository { + @override + _i3.Future> loadTodos() => + (super.noSuchMethod( + Invocation.method(#loadTodos, []), + returnValue: _i3.Future>.value( + <_i4.TodoEntity>[], + ), + returnValueForMissingStub: _i3.Future>.value( + <_i4.TodoEntity>[], + ), + ) + as _i3.Future>); + + @override + _i3.Future saveTodos(List<_i4.TodoEntity>? todos) => + (super.noSuchMethod( + Invocation.method(#saveTodos, [todos]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); +} diff --git a/redux/test/reducer_test.dart b/redux/test/reducer_test.dart index d22cfa55..c2559a8c 100644 --- a/redux/test/reducer_test.dart +++ b/redux/test/reducer_test.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter_test/flutter_test.dart'; import 'package:redux/redux.dart'; import 'package:redux_sample/actions/actions.dart'; @@ -34,7 +30,7 @@ void main() { store.dispatch(DeleteTodoAction(todo.id)); - expect(todosSelector(store.state), []); + expect(todosSelector(store.state), []); }); test('should update a todo in response to an UpdateTodoAction', () { diff --git a/redux/test/selectors_test.dart b/redux/test/selectors_test.dart index 0e14a591..c548915f 100644 --- a/redux/test/selectors_test.dart +++ b/redux/test/selectors_test.dart @@ -1,40 +1,24 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter_test/flutter_test.dart'; -import 'package:quiver/core.dart'; import 'package:redux_sample/models/models.dart'; import 'package:redux_sample/selectors/selectors.dart'; +import 'package:todos_app_core/todos_app_core.dart'; void main() { group('Selectors', () { test('should calculate the number of active todos', () { - final todos = [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]; + final todos = [Todo('a'), Todo('b'), Todo('c', complete: true)]; expect(numActiveSelector(todos), 2); }); test('should calculate the number of completed todos', () { - final todos = [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]; + final todos = [Todo('a'), Todo('b'), Todo('c', complete: true)]; expect(numCompletedSelector(todos), 1); }); test('should return all todos if the VisibilityFilter is all', () { - final todos = [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]; + final todos = [Todo('a'), Todo('b'), Todo('c', complete: true)]; expect(filteredTodosSelector(todos, VisibilityFilter.all), todos); }); @@ -43,11 +27,7 @@ void main() { final todo1 = Todo('a'); final todo2 = Todo('b'); final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; + final todos = [todo1, todo2, todo3]; expect(filteredTodosSelector(todos, VisibilityFilter.active), [ todo1, @@ -55,29 +35,25 @@ void main() { ]); }); - test('should return completed todos if the VisibilityFilter is completed', - () { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; + test( + 'should return completed todos if the VisibilityFilter is completed', + () { + final todo1 = Todo('a'); + final todo2 = Todo('b'); + final todo3 = Todo('c', complete: true); + final todos = [todo1, todo2, todo3]; - expect(filteredTodosSelector(todos, VisibilityFilter.completed), [todo3]); - }); + expect(filteredTodosSelector(todos, VisibilityFilter.completed), [ + todo3, + ]); + }, + ); test('should return an Optional todo based on id', () { final todo1 = Todo('a', id: '1'); final todo2 = Todo('b'); final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; + final todos = [todo1, todo2, todo3]; expect(todoSelector(todos, '1'), Optional.of(todo1)); }); @@ -86,13 +62,9 @@ void main() { final todo1 = Todo('a', id: '1'); final todo2 = Todo('b'); final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; + final todos = [todo1, todo2, todo3]; - expect(todoSelector(todos, '2'), Optional.absent()); + expect(todoSelector(todos, '2'), Optional.absent()); }); }); } diff --git a/redux/test_driver/integration_test.dart b/redux/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/redux/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/redux/test_driver/todo_app.dart b/redux/test_driver/todo_app.dart deleted file mode 100644 index 8f0a0f45..00000000 --- a/redux/test_driver/todo_app.dart +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter_driver/driver_extension.dart'; -import 'package:redux_sample/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/redux/test_driver/todo_app_test.dart b/redux/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/redux/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/redux/web/favicon.png b/redux/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/redux/web/favicon.png differ diff --git a/redux/web/icons/Icon-192.png b/redux/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/redux/web/icons/Icon-192.png differ diff --git a/redux/web/icons/Icon-512.png b/redux/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/redux/web/icons/Icon-512.png differ diff --git a/redux/web/icons/Icon-maskable-192.png b/redux/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/redux/web/icons/Icon-maskable-192.png differ diff --git a/redux/web/icons/Icon-maskable-512.png b/redux/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/redux/web/icons/Icon-maskable-512.png differ diff --git a/redux/web/index.html b/redux/web/index.html index 1f91a874..e90a99cc 100644 --- a/redux/web/index.html +++ b/redux/web/index.html @@ -1,10 +1,38 @@ + + + - redux + + + + + + + + + + + + + redux_sample + - + diff --git a/redux/web/manifest.json b/redux/web/manifest.json new file mode 100644 index 00000000..4895a337 --- /dev/null +++ b/redux/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "redux_sample", + "short_name": "redux_sample", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/redux/windows/.gitignore b/redux/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/redux/windows/.gitignore @@ -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/ diff --git a/redux/windows/CMakeLists.txt b/redux/windows/CMakeLists.txt new file mode 100644 index 00000000..da0a4cb9 --- /dev/null +++ b/redux/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(redux_sample 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 "redux_sample") + +# 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) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_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 "$") +# 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) diff --git a/redux/windows/flutter/CMakeLists.txt b/redux/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/redux/windows/flutter/CMakeLists.txt @@ -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} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/redux/windows/flutter/generated_plugin_registrant.cc b/redux/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/redux/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/redux/windows/flutter/generated_plugin_registrant.h b/redux/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/redux/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/redux/windows/flutter/generated_plugins.cmake b/redux/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/redux/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +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 $) + 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) diff --git a/redux/windows/runner/CMakeLists.txt b/redux/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/redux/windows/runner/CMakeLists.txt @@ -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) diff --git a/redux/windows/runner/Runner.rc b/redux/windows/runner/Runner.rc new file mode 100644 index 00000000..2335f91e --- /dev/null +++ b/redux/windows/runner/Runner.rc @@ -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", "com.example" "\0" + VALUE "FileDescription", "redux_sample" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "redux_sample" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "redux_sample.exe" "\0" + VALUE "ProductName", "redux_sample" "\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 diff --git a/redux/windows/runner/flutter_window.cpp b/redux/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/redux/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#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( + 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 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); +} diff --git a/redux/windows/runner/flutter_window.h b/redux/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/redux/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#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_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/redux/windows/runner/main.cpp b/redux/windows/runner/main.cpp new file mode 100644 index 00000000..2435434f --- /dev/null +++ b/redux/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 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"redux_sample", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/redux/windows/runner/resource.h b/redux/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/redux/windows/runner/resource.h @@ -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 diff --git a/redux/windows/runner/resources/app_icon.ico b/redux/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/redux/windows/runner/resources/app_icon.ico differ diff --git a/redux/windows/runner/runner.exe.manifest b/redux/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/redux/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/redux/windows/runner/utils.cpp b/redux/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/redux/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +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 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::vector 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; +} diff --git a/redux/windows/runner/utils.h b/redux/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/redux/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// 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, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/redux/windows/runner/win32_window.cpp b/redux/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/redux/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#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(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( + 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(origin.x), + static_cast(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(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(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(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( + 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)); + } +} diff --git a/redux/windows/runner/win32_window.h b/redux/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/redux/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// 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_ diff --git a/scoped_model/.flutter-plugins-dependencies b/scoped_model/.flutter-plugins-dependencies index d4d3c8cc..e577057b 100644 --- a/scoped_model/.flutter-plugins-dependencies +++ b/scoped_model/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"android":[{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":[]}],"date_created":"2020-02-10 11:24:35.748663","version":"1.14.7-pre.38"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"integration_test","path":"/Users/brian/fvm/versions/3.35.2/packages/integration_test/","native_build":true,"dependencies":[],"dev_dependency":true},{"name":"path_provider_foundation","path":"/Users/brian/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/brian/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"integration_test","path":"/Users/brian/fvm/versions/3.35.2/packages/integration_test/","native_build":true,"dependencies":[],"dev_dependency":true},{"name":"path_provider_android","path":"/Users/brian/.pub-cache/hosted/pub.dev/path_provider_android-2.2.18/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/Users/brian/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.12/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"path_provider_foundation","path":"/Users/brian/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/brian/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"path_provider_linux","path":"/Users/brian/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/Users/brian/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false}],"windows":[{"name":"path_provider_windows","path":"/Users/brian/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/Users/brian/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false}],"web":[{"name":"shared_preferences_web","path":"/Users/brian/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2025-09-04 15:35:49.303722","version":"3.35.2","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/scoped_model/.metadata b/scoped_model/.metadata index 1b5cec02..05a8ab44 100644 --- a/scoped_model/.metadata +++ b/scoped_model/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: 27321ebbad34b0a3fafe99fac037102196d655ff - channel: stable + revision: "05db9689081f091050f01aed79f04dce0c750154" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: android + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: ios + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: linux + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: macos + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: web + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: windows + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/scoped_model/analysis_options.yaml b/scoped_model/analysis_options.yaml new file mode 100644 index 00000000..134f2137 --- /dev/null +++ b/scoped_model/analysis_options.yaml @@ -0,0 +1,34 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# 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 +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + # The lint rules applied to this project can be customized in the + # 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 + # and their documentation is published at https://dart.dev/lints. + # + # 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 + # 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 + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/scoped_model/android/.gitignore b/scoped_model/android/.gitignore index bc2100d8..be3943c9 100644 --- a/scoped_model/android/.gitignore +++ b/scoped_model/android/.gitignore @@ -5,3 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/scoped_model/android/app/build.gradle b/scoped_model/android/app/build.gradle deleted file mode 100644 index e16427c0..00000000 --- a/scoped_model/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.scoped_model" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/scoped_model/android/app/build.gradle.kts b/scoped_model/android/app/build.gradle.kts new file mode 100644 index 00000000..4bfa5291 --- /dev/null +++ b/scoped_model/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.scoped_model_sample" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.scoped_model_sample" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/scoped_model/android/app/src/debug/AndroidManifest.xml b/scoped_model/android/app/src/debug/AndroidManifest.xml index 321ebbeb..399f6981 100644 --- a/scoped_model/android/app/src/debug/AndroidManifest.xml +++ b/scoped_model/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/scoped_model/android/app/src/main/AndroidManifest.xml b/scoped_model/android/app/src/main/AndroidManifest.xml index 59c10228..3f727faf 100644 --- a/scoped_model/android/app/src/main/AndroidManifest.xml +++ b/scoped_model/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,25 @@ - - + + + @@ -27,4 +31,15 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + diff --git a/scoped_model/android/app/src/main/kotlin/com/example/scoped_model/MainActivity.kt b/scoped_model/android/app/src/main/kotlin/com/example/scoped_model/MainActivity.kt deleted file mode 100644 index 2334c261..00000000 --- a/scoped_model/android/app/src/main/kotlin/com/example/scoped_model/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.scoped_model - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/scoped_model/android/app/src/main/kotlin/com/example/scoped_model_sample/MainActivity.kt b/scoped_model/android/app/src/main/kotlin/com/example/scoped_model_sample/MainActivity.kt new file mode 100644 index 00000000..10a878a8 --- /dev/null +++ b/scoped_model/android/app/src/main/kotlin/com/example/scoped_model_sample/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.scoped_model_sample + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/scoped_model/android/app/src/main/res/drawable-v21/launch_background.xml b/scoped_model/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/scoped_model/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/scoped_model/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/scoped_model/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index a3f285f9..db77bb4b 100644 Binary files a/scoped_model/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/scoped_model/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/scoped_model/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/scoped_model/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 5e6f3ac6..17987b79 100644 Binary files a/scoped_model/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/scoped_model/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/scoped_model/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/scoped_model/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 144d60be..09d43914 100644 Binary files a/scoped_model/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/scoped_model/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/scoped_model/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/scoped_model/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index deafae2d..d5f1c8d3 100644 Binary files a/scoped_model/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/scoped_model/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/scoped_model/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/scoped_model/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index d5614ac8..4d6372ee 100644 Binary files a/scoped_model/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/scoped_model/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/scoped_model/android/app/src/main/res/values-night/styles.xml b/scoped_model/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/scoped_model/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/scoped_model/android/app/src/main/res/values/styles.xml b/scoped_model/android/app/src/main/res/values/styles.xml index 00fa4417..cb1ef880 100644 --- a/scoped_model/android/app/src/main/res/values/styles.xml +++ b/scoped_model/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ - + + diff --git a/scoped_model/android/app/src/profile/AndroidManifest.xml b/scoped_model/android/app/src/profile/AndroidManifest.xml index 321ebbeb..399f6981 100644 --- a/scoped_model/android/app/src/profile/AndroidManifest.xml +++ b/scoped_model/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/scoped_model/android/build.gradle b/scoped_model/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/scoped_model/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/scoped_model/android/build.gradle.kts b/scoped_model/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/scoped_model/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/scoped_model/android/gradle.properties b/scoped_model/android/gradle.properties index 38c8d454..f018a618 100644 --- a/scoped_model/android/gradle.properties +++ b/scoped_model/android/gradle.properties @@ -1,4 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/scoped_model/android/gradle/wrapper/gradle-wrapper.properties b/scoped_model/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..ac3b4792 100644 --- a/scoped_model/android/gradle/wrapper/gradle-wrapper.properties +++ b/scoped_model/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/scoped_model/android/gradlew.bat b/scoped_model/android/gradlew.bat index 8a0b282a..aec99730 100644 --- a/scoped_model/android/gradlew.bat +++ b/scoped_model/android/gradlew.bat @@ -1,90 +1,90 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/scoped_model/android/settings.gradle b/scoped_model/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/scoped_model/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/scoped_model/android/settings.gradle.kts b/scoped_model/android/settings.gradle.kts new file mode 100644 index 00000000..fb605bc8 --- /dev/null +++ b/scoped_model/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/scoped_model/integration_test/app_test.dart b/scoped_model/integration_test/app_test.dart new file mode 100644 index 00000000..9ad90a36 --- /dev/null +++ b/scoped_model/integration_test/app_test.dart @@ -0,0 +1,19 @@ +import 'package:integration_tests/integration_tests.dart' as integration_tests; +import 'package:scoped_model_sample/app.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; + +void main() { + integration_tests.run( + appBuilder: () async { + return ScopedModelApp( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'scoped_model_test_${DateTime.now().toIso8601String()}', + await SharedPreferences.getInstance(), + ), + ), + ); + }, + ); +} diff --git a/scoped_model/ios/.gitignore b/scoped_model/ios/.gitignore index e96ef602..7a7f9873 100644 --- a/scoped_model/ios/.gitignore +++ b/scoped_model/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/scoped_model/ios/Flutter/AppFrameworkInfo.plist b/scoped_model/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f78..1dc6cf76 100644 --- a/scoped_model/ios/Flutter/AppFrameworkInfo.plist +++ b/scoped_model/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 13.0 diff --git a/scoped_model/ios/Flutter/Debug.xcconfig b/scoped_model/ios/Flutter/Debug.xcconfig index e8efba11..ec97fc6f 100644 --- a/scoped_model/ios/Flutter/Debug.xcconfig +++ b/scoped_model/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/scoped_model/ios/Flutter/Release.xcconfig b/scoped_model/ios/Flutter/Release.xcconfig index 399e9340..c4855bfe 100644 --- a/scoped_model/ios/Flutter/Release.xcconfig +++ b/scoped_model/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/scoped_model/ios/Podfile b/scoped_model/ios/Podfile index b30a428b..620e46eb 100644 --- a/scoped_model/ios/Podfile +++ b/scoped_model/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -10,81 +10,34 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - generated_key_values + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' +flutter_ios_podfile_setup - # Plugin Pods +target 'Runner' do + use_frameworks! - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths end end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/scoped_model/ios/Runner.xcodeproj/project.pbxproj b/scoped_model/ios/Runner.xcodeproj/project.pbxproj index 1ccce2d4..cc33e9e1 100644 --- a/scoped_model/ios/Runner.xcodeproj/project.pbxproj +++ b/scoped_model/ios/Runner.xcodeproj/project.pbxproj @@ -3,22 +3,29 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -26,8 +33,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -37,14 +42,14 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -57,20 +62,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -84,6 +93,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -91,6 +101,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -102,7 +113,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -111,16 +121,26 @@ path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; @@ -147,9 +167,14 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -157,7 +182,7 @@ }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -170,11 +195,19 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -191,20 +224,23 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -220,6 +256,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -231,6 +275,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -253,9 +305,9 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -285,6 +337,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -293,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -309,18 +362,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModel; + PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModelSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -328,11 +377,58 @@ }; name = Profile; }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModelSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModelSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModelSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -362,6 +458,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -376,7 +473,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -386,9 +483,9 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -418,6 +515,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -426,11 +524,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -443,18 +542,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModel; + PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModelSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -470,18 +565,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModel; + PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModelSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -492,6 +583,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/scoped_model/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/scoped_model/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/scoped_model/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/scoped_model/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/scoped_model/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/scoped_model/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/scoped_model/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/scoped_model/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/scoped_model/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/scoped_model/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/scoped_model/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/scoped_model/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..e3773d42 100644 --- a/scoped_model/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/scoped_model/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + + + + + @@ -61,8 +73,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - + + + + IDEDidComputeMac32BitWarning + + + diff --git a/scoped_model/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/scoped_model/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/scoped_model/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/scoped_model/ios/Runner/AppDelegate.swift b/scoped_model/ios/Runner/AppDelegate.swift index 70693e4a..62666446 100644 --- a/scoped_model/ios/Runner/AppDelegate.swift +++ b/scoped_model/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ -import UIKit import Flutter +import UIKit -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d22f10b2..d36b1fab 100644 --- a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -107,6 +107,12 @@ "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" } ], "info" : { diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 980e5ad6..7353c41e 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index fd870289..797d452e 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 75e84cd1..6ed2d933 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 03ab8a84..4cd7b009 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index a03431cb..fe730945 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index f47613ee..321773cd 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 7f2230a9..797d452e 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 42315c6d..502f463a 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index f9882cc0..0ec30343 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 45537513..0ec30343 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 6360ea17..e9f5fea2 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 152d5e12..84ac32ae 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 310b0b8f..8953cba0 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 092b7bfe..0467bf12 100644 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/scoped_model/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/scoped_model/ios/Runner/Info.plist b/scoped_model/ios/Runner/Info.plist index c683ec62..bf226dd4 100644 --- a/scoped_model/ios/Runner/Info.plist +++ b/scoped_model/ios/Runner/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Scoped Model Sample CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -11,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - scoped_model + scoped_model_sample CFBundlePackageType APPL CFBundleShortVersionString @@ -39,7 +41,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/scoped_model/ios/Runner/Runner-Bridging-Header.h b/scoped_model/ios/Runner/Runner-Bridging-Header.h index 7335fdf9..308a2a56 100644 --- a/scoped_model/ios/Runner/Runner-Bridging-Header.h +++ b/scoped_model/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file +#import "GeneratedPluginRegistrant.h" diff --git a/scoped_model/ios/RunnerTests/RunnerTests.swift b/scoped_model/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/scoped_model/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/scoped_model/lib/app.dart b/scoped_model/lib/app.dart index 1828cf85..645a6d79 100644 --- a/scoped_model/lib/app.dart +++ b/scoped_model/lib/app.dart @@ -1,9 +1,4 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:meta/meta.dart'; import 'package:scoped_model/scoped_model.dart'; import 'package:scoped_model_sample/localization.dart'; import 'package:scoped_model_sample/screens/add_edit_screen.dart'; @@ -15,16 +10,15 @@ import 'package:todos_repository_core/todos_repository_core.dart'; class ScopedModelApp extends StatelessWidget { final TodosRepository repository; - ScopedModelApp({ - @required this.repository, - }); + const ScopedModelApp({super.key, required this.repository}); @override Widget build(BuildContext context) { var app = MaterialApp( onGenerateTitle: (context) => ScopedModelLocalizations.of(context).appTitle, - theme: ArchSampleTheme.theme, + theme: ArchSampleTheme.lightTheme, + darkTheme: ArchSampleTheme.darkTheme, localizationsDelegates: [ ArchSampleLocalizationsDelegate(), ScopedModelLocalizationsDelegate(), @@ -36,9 +30,7 @@ class ScopedModelApp extends StatelessWidget { ); return ScopedModel( - model: TodoListModel( - repository: repository, - ), + model: TodoListModel(repository: repository), child: app, ); } diff --git a/scoped_model/lib/localization.dart b/scoped_model/lib/localization.dart index e2b43d69..9735f4a8 100644 --- a/scoped_model/lib/localization.dart +++ b/scoped_model/lib/localization.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; @@ -9,7 +5,9 @@ import 'package:flutter/material.dart'; class ScopedModelLocalizations { static ScopedModelLocalizations of(BuildContext context) { return Localizations.of( - context, ScopedModelLocalizations); + context, + ScopedModelLocalizations, + )!; } String get appTitle => 'scoped_model example'; diff --git a/scoped_model/lib/main.dart b/scoped_model/lib/main.dart index d224962e..cf2eebf3 100644 --- a/scoped_model/lib/main.dart +++ b/scoped_model/lib/main.dart @@ -1,23 +1,23 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; import 'package:scoped_model_sample/app.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; -void main() { +void main() async { WidgetsFlutterBinding.ensureInitialized(); - var todoRepo = const LocalStorageRepository( - localStorage: FileStorage( - 'scoped_model_todos', - getApplicationDocumentsDirectory, + final localStorage = kIsWeb + ? KeyValueStorage( + 'scoped_model_todos', + await SharedPreferences.getInstance(), + ) + : FileStorage('scoped_model_todos', getApplicationDocumentsDirectory); + + runApp( + ScopedModelApp( + repository: LocalStorageRepository(localStorage: localStorage), ), ); - - runApp(ScopedModelApp( - repository: todoRepo, - )); } diff --git a/scoped_model/lib/models.dart b/scoped_model/lib/models.dart index 699321cb..8f87d6fa 100644 --- a/scoped_model/lib/models.dart +++ b/scoped_model/lib/models.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -15,8 +11,8 @@ class Todo { final String note; final String task; - Todo(this.task, {this.complete = false, this.note = '', String id}) - : id = id ?? Uuid().generateV4(); + Todo(this.task, {this.complete = false, this.note = '', String? id}) + : id = id ?? Uuid().generateV4(); @override int get hashCode => @@ -44,13 +40,13 @@ class Todo { static Todo fromEntity(TodoEntity entity) { return Todo( entity.task, - complete: entity.complete ?? false, + complete: entity.complete, note: entity.note, id: entity.id, ); } - Todo copy({String task, bool complete, String note, String id}) { + Todo copy({String? task, bool? complete, String? note, String? id}) { return Todo( task ?? this.task, complete: complete ?? this.complete, diff --git a/scoped_model/lib/screens/add_edit_screen.dart b/scoped_model/lib/screens/add_edit_screen.dart index d50679b0..890b5dc1 100644 --- a/scoped_model/lib/screens/add_edit_screen.dart +++ b/scoped_model/lib/screens/add_edit_screen.dart @@ -1,33 +1,25 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:scoped_model/scoped_model.dart'; import 'package:scoped_model_sample/models.dart'; import 'package:scoped_model_sample/todo_list_model.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class AddEditScreen extends StatefulWidget { - final String todoId; + final String? todoId; + + const AddEditScreen({super.key = ArchSampleKeys.addTodoScreen, this.todoId}); - AddEditScreen({ - Key key, - this.todoId, - }) : super(key: key ?? ArchSampleKeys.addTodoScreen); @override - _AddEditScreenState createState() => _AddEditScreenState(); + AddEditScreenState createState() => AddEditScreenState(); } -class _AddEditScreenState extends State { +class AddEditScreenState extends State { static final GlobalKey _formKey = GlobalKey(); - String _task; - String _note; + late String _task; + late String _note; - bool get isEditing => widget.todoId != null; + bool get isEditing => widget.todoId != null && widget.todoId!.isNotEmpty; @override Widget build(BuildContext context) { @@ -36,68 +28,69 @@ class _AddEditScreenState extends State { return Scaffold( appBar: AppBar( - title: Text( - isEditing ? localizations.editTodo : localizations.addTodo, - ), + title: Text(isEditing ? localizations.editTodo : localizations.addTodo), ), body: Padding( padding: EdgeInsets.all(16.0), child: Form( key: _formKey, - autovalidate: false, - onWillPop: () { - return Future(() => true); - }, + autovalidateMode: AutovalidateMode.always, + canPop: true, child: ScopedModelDescendant( - builder: (BuildContext context, Widget child, TodoListModel model) { - var task = model.todoById(widget.todoId); - return ListView( - children: [ - TextFormField( - initialValue: task?.task ?? '', - key: ArchSampleKeys.taskField, - autofocus: !isEditing, - style: textTheme.headline, - decoration: InputDecoration( - hintText: localizations.newTodoHint, - ), - validator: (val) { - return val.trim().isEmpty - ? localizations.emptyTodoError - : null; - }, - onSaved: (value) => _task = value, - ), - TextFormField( - initialValue: task?.note ?? '', - key: ArchSampleKeys.noteField, - maxLines: 10, - style: textTheme.subhead, - decoration: InputDecoration( - hintText: localizations.notesHint, - ), - onSaved: (value) => _note = value, - ) - ], - ); - }, + builder: + (BuildContext context, Widget? child, TodoListModel model) { + final task = isEditing + ? model.todoById(widget.todoId!) + : null; + + return ListView( + children: [ + TextFormField( + initialValue: task?.task ?? '', + key: ArchSampleKeys.taskField, + autofocus: !isEditing, + style: textTheme.titleLarge, + decoration: InputDecoration( + hintText: localizations.newTodoHint, + ), + validator: (val) { + return val != null && val.trim().isEmpty + ? localizations.emptyTodoError + : null; + }, + onSaved: (value) => _task = value ?? '', + ), + TextFormField( + initialValue: task?.note ?? '', + key: ArchSampleKeys.noteField, + maxLines: 10, + style: textTheme.titleMedium, + decoration: InputDecoration( + hintText: localizations.notesHint, + ), + onSaved: (value) => _note = value ?? '', + ), + ], + ); + }, ), ), ), floatingActionButton: FloatingActionButton( - key: - isEditing ? ArchSampleKeys.saveTodoFab : ArchSampleKeys.saveNewTodo, + key: isEditing + ? ArchSampleKeys.saveTodoFab + : ArchSampleKeys.saveNewTodo, tooltip: isEditing ? localizations.saveChanges : localizations.addTodo, child: Icon(isEditing ? Icons.check : Icons.add), onPressed: () { final form = _formKey.currentState; - if (form.validate()) { + if (form!.validate()) { form.save(); var model = TodoListModel.of(context); if (isEditing) { - var todo = model.todoById(widget.todoId); - model.updateTodo(todo.copy(task: _task, note: _note)); + var todo = model.todoById(widget.todoId!); + model.updateTodo(todo!.copy(task: _task, note: _note)); } else { model.addTodo(Todo(_task, note: _note)); } diff --git a/scoped_model/lib/screens/detail_screen.dart b/scoped_model/lib/screens/detail_screen.dart index 3949ec68..a42cf2b9 100644 --- a/scoped_model/lib/screens/detail_screen.dart +++ b/scoped_model/lib/screens/detail_screen.dart @@ -1,21 +1,17 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:scoped_model/scoped_model.dart'; import 'package:scoped_model_sample/models.dart'; import 'package:scoped_model_sample/screens/add_edit_screen.dart'; import 'package:scoped_model_sample/todo_list_model.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class DetailScreen extends StatelessWidget { final String todoId; - DetailScreen({ - @required this.todoId, - }) : super(key: ArchSampleKeys.todoDetailsScreen); + const DetailScreen({ + super.key = ArchSampleKeys.todoDetailsScreen, + required this.todoId, + }); @override Widget build(BuildContext context) { @@ -35,7 +31,7 @@ class DetailScreen extends StatelessWidget { model.removeTodo(todo); Navigator.pop(context, todo); }, - ) + ), ], ), body: Padding( @@ -60,21 +56,18 @@ class DetailScreen extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), + padding: EdgeInsets.only(top: 8.0, bottom: 16.0), child: Text( todo.task, key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, ), ), Text( todo.note, key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) + style: Theme.of(context).textTheme.titleMedium, + ), ], ), ), @@ -85,11 +78,10 @@ class DetailScreen extends StatelessWidget { ), floatingActionButton: FloatingActionButton( tooltip: ArchSampleLocalizations.of(context).editTodo, - child: Icon(Icons.edit), key: ArchSampleKeys.editTodoFab, onPressed: () { Navigator.of(context).push( - MaterialPageRoute( + MaterialPageRoute( builder: (context) { return AddEditScreen( todoId: todoId, @@ -99,6 +91,7 @@ class DetailScreen extends StatelessWidget { ), ); }, + child: Icon(Icons.edit), ), ); }, diff --git a/scoped_model/lib/screens/home_screen.dart b/scoped_model/lib/screens/home_screen.dart index 60fa8e2f..cdb611df 100644 --- a/scoped_model/lib/screens/home_screen.dart +++ b/scoped_model/lib/screens/home_screen.dart @@ -1,21 +1,17 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:scoped_model_sample/localization.dart'; import 'package:scoped_model_sample/models.dart'; import 'package:scoped_model_sample/widgets/extra_actions_button.dart'; import 'package:scoped_model_sample/widgets/filter_button.dart'; import 'package:scoped_model_sample/widgets/stats_counter.dart'; import 'package:scoped_model_sample/widgets/todo_list.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class HomeScreen extends StatefulWidget { - HomeScreen() : super(key: ArchSampleKeys.homeScreen); + const HomeScreen({super.key}); @override - State createState() { + State createState() { return HomeScreenState(); } } @@ -30,7 +26,7 @@ class HomeScreenState extends State { title: Text(ScopedModelLocalizations.of(context).appTitle), actions: [ FilterButton(isActive: _activeTab == AppTab.todos), - ExtraActionsButton() + ExtraActionsButton(), ], ), body: _activeTab == AppTab.todos ? TodoList() : StatsCounter(), @@ -39,8 +35,8 @@ class HomeScreenState extends State { onPressed: () { Navigator.pushNamed(context, ArchSampleRoutes.addTodo); }, - child: Icon(Icons.add), tooltip: ArchSampleLocalizations.of(context).addTodo, + child: Icon(Icons.add), ), bottomNavigationBar: BottomNavigationBar( key: ArchSampleKeys.tabs, @@ -56,11 +52,9 @@ class HomeScreenState extends State { ? ArchSampleKeys.statsTab : ArchSampleKeys.todoTab, ), - title: Text( - tab == AppTab.stats - ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos, - ), + label: tab == AppTab.stats + ? ArchSampleLocalizations.of(context).stats + : ArchSampleLocalizations.of(context).todos, ); }).toList(), ), diff --git a/scoped_model/lib/todo_list_model.dart b/scoped_model/lib/todo_list_model.dart index a4ec9860..a95fb61b 100644 --- a/scoped_model/lib/todo_list_model.dart +++ b/scoped_model/lib/todo_list_model.dart @@ -1,11 +1,7 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; +import 'package:collection/collection.dart'; import 'package:flutter/widgets.dart'; -import 'package:meta/meta.dart'; import 'package:scoped_model/scoped_model.dart'; import 'package:scoped_model_sample/models.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -30,8 +26,8 @@ class TodoListModel extends Model { bool get isLoading => _isLoading; - TodoListModel({@required this.repository, VisibilityFilter activeFilter}) - : _activeFilter = activeFilter ?? VisibilityFilter.all; + TodoListModel({required this.repository, VisibilityFilter? activeFilter}) + : _activeFilter = activeFilter ?? VisibilityFilter.all; /// Wraps [ScopedModel.of] for this [Model]. See [ScopedModel.of] for more static TodoListModel of(BuildContext context) => @@ -47,32 +43,34 @@ class TodoListModel extends Model { /// Loads remote data /// /// Call this initially and when the user manually refreshes - Future loadTodos() { + Future loadTodos() { _isLoading = true; notifyListeners(); - return repository.loadTodos().then((loadedTodos) { - _todos = loadedTodos.map(Todo.fromEntity).toList(); - _isLoading = false; - notifyListeners(); - }).catchError((err) { - _isLoading = false; - _todos = []; - notifyListeners(); - }); + return repository + .loadTodos() + .then((loadedTodos) { + _todos = loadedTodos.map(Todo.fromEntity).toList(); + _isLoading = false; + notifyListeners(); + }) + .catchError((err) { + _isLoading = false; + _todos = []; + notifyListeners(); + }); } List get filteredTodos => _todos.where((todo) { - switch (activeFilter) { - case VisibilityFilter.active: - return !todo.complete; - case VisibilityFilter.completed: - return todo.complete; - case VisibilityFilter.all: - default: - return true; - } - }).toList(); + switch (activeFilter) { + case VisibilityFilter.active: + return !todo.complete; + case VisibilityFilter.completed: + return todo.complete; + case VisibilityFilter.all: + return true; + } + }).toList(); void clearCompleted() { _todos.removeWhere((todo) => todo.complete); @@ -88,8 +86,6 @@ class TodoListModel extends Model { /// updates a [Todo] by replacing the item with the same id by the parameter [todo] void updateTodo(Todo todo) { - assert(todo != null); - assert(todo.id != null); var oldTodo = _todos.firstWhere((it) => it.id == todo.id); var replaceIndex = _todos.indexOf(oldTodo); _todos.replaceRange(replaceIndex, replaceIndex + 1, [todo]); @@ -113,8 +109,8 @@ class TodoListModel extends Model { repository.saveTodos(_todos.map((it) => it.toEntity()).toList()); } - Todo todoById(String id) { - return _todos.firstWhere((it) => it.id == id, orElse: () => null); + Todo? todoById(String id) { + return _todos.firstWhereOrNull((it) => it.id == id); } } diff --git a/scoped_model/lib/widgets/extra_actions_button.dart b/scoped_model/lib/widgets/extra_actions_button.dart index 4a024228..6710277b 100644 --- a/scoped_model/lib/widgets/extra_actions_button.dart +++ b/scoped_model/lib/widgets/extra_actions_button.dart @@ -1,46 +1,43 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:scoped_model/scoped_model.dart'; import 'package:scoped_model_sample/models.dart'; import 'package:scoped_model_sample/todo_list_model.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class ExtraActionsButton extends StatelessWidget { - ExtraActionsButton({ - Key key, - }) : super(key: key); + const ExtraActionsButton({super.key}); @override Widget build(BuildContext context) { return ScopedModelDescendant( - builder: (BuildContext context, Widget child, TodoListModel model) { - return PopupMenuButton( - key: ArchSampleKeys.extraActionsButton, - onSelected: (action) { - if (action == ExtraAction.toggleAllComplete) { - model.toggleAll(); - } else if (action == ExtraAction.clearCompleted) { - model.clearCompleted(); - } - }, - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - key: ArchSampleKeys.toggleAll, - value: ExtraAction.toggleAllComplete, - child: Text(model.todos.any((it) => !it.complete) - ? ArchSampleLocalizations.of(context).markAllIncomplete - : ArchSampleLocalizations.of(context).markAllComplete), - ), - PopupMenuItem( - key: ArchSampleKeys.clearCompleted, - value: ExtraAction.clearCompleted, - child: Text(ArchSampleLocalizations.of(context).clearCompleted), - ), - ], - ); - }); + builder: (BuildContext context, Widget? child, TodoListModel model) { + return PopupMenuButton( + key: ArchSampleKeys.extraActionsButton, + onSelected: (action) { + if (action == ExtraAction.toggleAllComplete) { + model.toggleAll(); + } else if (action == ExtraAction.clearCompleted) { + model.clearCompleted(); + } + }, + itemBuilder: (BuildContext context) => >[ + PopupMenuItem( + key: ArchSampleKeys.toggleAll, + value: ExtraAction.toggleAllComplete, + child: Text( + model.todos.any((it) => !it.complete) + ? ArchSampleLocalizations.of(context).markAllIncomplete + : ArchSampleLocalizations.of(context).markAllComplete, + ), + ), + PopupMenuItem( + key: ArchSampleKeys.clearCompleted, + value: ExtraAction.clearCompleted, + child: Text(ArchSampleLocalizations.of(context).clearCompleted), + ), + ], + ); + }, + ); } } diff --git a/scoped_model/lib/widgets/filter_button.dart b/scoped_model/lib/widgets/filter_button.dart index 690ee73b..c9b4a50e 100644 --- a/scoped_model/lib/widgets/filter_button.dart +++ b/scoped_model/lib/widgets/filter_button.dart @@ -1,16 +1,12 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:scoped_model/scoped_model.dart'; import 'package:scoped_model_sample/todo_list_model.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class FilterButton extends StatelessWidget { final bool isActive; - FilterButton({this.isActive, Key key}) : super(key: key); + const FilterButton({required this.isActive, super.key}); @override Widget build(BuildContext context) { @@ -18,7 +14,7 @@ class FilterButton extends StatelessWidget { opacity: isActive ? 1.0 : 0.0, duration: Duration(milliseconds: 150), child: ScopedModelDescendant( - builder: (BuildContext context, Widget child, TodoListModel model) { + builder: (BuildContext context, Widget? child, TodoListModel model) { return PopupMenuButton( key: ArchSampleKeys.filterButton, tooltip: ArchSampleLocalizations.of(context).filterTodos, @@ -34,12 +30,13 @@ class FilterButton extends StatelessWidget { } List> _items( - BuildContext context, TodoListModel model) { - final activeStyle = Theme.of(context) - .textTheme - .body1 - .copyWith(color: Theme.of(context).accentColor); - final defaultStyle = Theme.of(context).textTheme.body1; + BuildContext context, + TodoListModel model, + ) { + final defaultStyle = Theme.of(context).textTheme.bodyMedium; + final activeStyle = defaultStyle?.copyWith( + color: Theme.of(context).colorScheme.secondary, + ); return [ PopupMenuItem( diff --git a/scoped_model/lib/widgets/stats_counter.dart b/scoped_model/lib/widgets/stats_counter.dart index 9a9df978..98147604 100644 --- a/scoped_model/lib/widgets/stats_counter.dart +++ b/scoped_model/lib/widgets/stats_counter.dart @@ -1,16 +1,11 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:scoped_model/scoped_model.dart'; import 'package:scoped_model_sample/models.dart'; import 'package:scoped_model_sample/todo_list_model.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class StatsCounter extends StatelessWidget { - StatsCounter() : super(key: ArchSampleKeys.statsCounter); + const StatsCounter({super.key = ArchSampleKeys.statsCounter}); bool isActive(Todo todo) => !todo.complete; @@ -20,46 +15,47 @@ class StatsCounter extends StatelessWidget { Widget build(BuildContext context) { return Center( child: ScopedModelDescendant( - builder: (context, child, model) { - var numCompleted = model.todos.where(isCompleted).toList().length; - var numActive = model.todos.where(isActive).toList().length; + builder: (context, child, model) { + var numCompleted = model.todos.where(isCompleted).toList().length; + var numActive = model.todos.where(isActive).toList().length; - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 8.0), + child: Text( + ArchSampleLocalizations.of(context).completedTodos, + style: Theme.of(context).textTheme.titleLarge, + ), ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '$numCompleted', - key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, + Padding( + padding: EdgeInsets.only(bottom: 24.0), + child: Text( + '$numCompleted', + key: ArchSampleKeys.statsNumCompleted, + style: Theme.of(context).textTheme.titleMedium, + ), ), - ), - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, + Padding( + padding: EdgeInsets.only(bottom: 8.0), + child: Text( + ArchSampleLocalizations.of(context).activeTodos, + style: Theme.of(context).textTheme.titleLarge, + ), ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '$numActive', - key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, + Padding( + padding: EdgeInsets.only(bottom: 24.0), + child: Text( + '$numActive', + key: ArchSampleKeys.statsNumActive, + style: Theme.of(context).textTheme.titleMedium, + ), ), - ) - ], - ); - }), + ], + ); + }, + ), ); } } diff --git a/scoped_model/lib/widgets/todo_item.dart b/scoped_model/lib/widgets/todo_item.dart index c4985e50..c4eeb2bd 100644 --- a/scoped_model/lib/widgets/todo_item.dart +++ b/scoped_model/lib/widgets/todo_item.dart @@ -1,23 +1,19 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:scoped_model_sample/models.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class TodoItem extends StatelessWidget { final DismissDirectionCallback onDismissed; final GestureTapCallback onTap; - final ValueChanged onCheckboxChanged; + final ValueChanged onCheckboxChanged; final Todo todo; - TodoItem({ - @required this.onDismissed, - @required this.onTap, - @required this.onCheckboxChanged, - @required this.todo, + const TodoItem({ + super.key, + required this.onDismissed, + required this.onTap, + required this.onCheckboxChanged, + required this.todo, }); @override @@ -35,14 +31,14 @@ class TodoItem extends StatelessWidget { title: Text( todo.task, key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), subtitle: Text( todo.note, key: ArchSampleKeys.todoItemNote(todo.id), maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ); diff --git a/scoped_model/lib/widgets/todo_list.dart b/scoped_model/lib/widgets/todo_list.dart index 2e07afea..f00cd2ef 100644 --- a/scoped_model/lib/widgets/todo_list.dart +++ b/scoped_model/lib/widgets/todo_list.dart @@ -1,17 +1,13 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:scoped_model/scoped_model.dart'; import 'package:scoped_model_sample/models.dart'; import 'package:scoped_model_sample/screens/detail_screen.dart'; import 'package:scoped_model_sample/todo_list_model.dart'; import 'package:scoped_model_sample/widgets/todo_item.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class TodoList extends StatelessWidget { - TodoList({Key key}) : super(key: key); + const TodoList({super.key}); @override Widget build(BuildContext context) { @@ -26,9 +22,7 @@ class TodoList extends StatelessWidget { Center get _buildLoading { return Center( - child: CircularProgressIndicator( - key: ArchSampleKeys.todosLoading, - ), + child: CircularProgressIndicator(key: ArchSampleKeys.todosLoading), ); } @@ -47,19 +41,19 @@ class TodoList extends StatelessWidget { _removeTodo(context, todo); }, onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) { - return DetailScreen( - todoId: todo.id, - ); - }, - ), - ).then((todo) { - if (todo is Todo) { - _showUndoSnackbar(context, todo); - } - }); + Navigator.of(context) + .push( + MaterialPageRoute( + builder: (_) { + return DetailScreen(todoId: todo.id); + }, + ), + ) + .then((todo) { + if (todo is Todo && context.mounted) { + _showUndoSnackbar(context, todo); + } + }); }, onCheckboxChanged: (complete) { var toggled = todo.copy(complete: !todo.complete); @@ -77,7 +71,7 @@ class TodoList extends StatelessWidget { } void _showUndoSnackbar(BuildContext context, Todo todo) { - Scaffold.of(context).showSnackBar( + ScaffoldMessenger.of(context).showSnackBar( SnackBar( key: ArchSampleKeys.snackbar, duration: Duration(seconds: 2), diff --git a/scoped_model/lib/widgets/typedefs.dart b/scoped_model/lib/widgets/typedefs.dart index 838fa8af..a4ad305b 100644 --- a/scoped_model/lib/widgets/typedefs.dart +++ b/scoped_model/lib/widgets/typedefs.dart @@ -1,17 +1,14 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:scoped_model_sample/models.dart'; typedef TodoAdder = void Function(Todo todo); typedef TodoRemover = void Function(Todo todo); -typedef TodoUpdater = void Function( - Todo todo, { - bool complete, - String id, - String note, - String task, -}); +typedef TodoUpdater = + void Function( + Todo todo, { + bool complete, + String id, + String note, + String task, + }); diff --git a/scoped_model/linux/.gitignore b/scoped_model/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/scoped_model/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/scoped_model/linux/CMakeLists.txt b/scoped_model/linux/CMakeLists.txt new file mode 100644 index 00000000..994a5b1a --- /dev/null +++ b/scoped_model/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +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 "scoped_model_sample") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.scoped_model_sample") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +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() + +# 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() + +# 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_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# 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 +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# 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() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +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) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/scoped_model/linux/flutter/CMakeLists.txt b/scoped_model/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/scoped_model/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +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. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# 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/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter 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. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/scoped_model/linux/flutter/generated_plugin_registrant.cc b/scoped_model/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e71a16d2 --- /dev/null +++ b/scoped_model/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/scoped_model/linux/flutter/generated_plugin_registrant.h b/scoped_model/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/scoped_model/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/scoped_model/linux/flutter/generated_plugins.cmake b/scoped_model/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/scoped_model/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + 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}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/scoped_model/linux/runner/CMakeLists.txt b/scoped_model/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/scoped_model/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "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 +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/scoped_model/linux/runner/main.cc b/scoped_model/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/scoped_model/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/scoped_model/linux/runner/my_application.cc b/scoped_model/linux/runner/my_application.cc new file mode 100644 index 00000000..cf1dad04 --- /dev/null +++ b/scoped_model/linux/runner/my_application.cc @@ -0,0 +1,144 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView *view) +{ + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // 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 + // desktop). + // 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. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "scoped_model_sample"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "scoped_model_sample"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/scoped_model/linux/runner/my_application.h b/scoped_model/linux/runner/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/scoped_model/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/scoped_model/macos/.gitignore b/scoped_model/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/scoped_model/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/scoped_model/macos/Flutter/Flutter-Debug.xcconfig b/scoped_model/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/scoped_model/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/scoped_model/macos/Flutter/Flutter-Release.xcconfig b/scoped_model/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/scoped_model/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/scoped_model/macos/Flutter/GeneratedPluginRegistrant.swift b/scoped_model/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b8e2b22f --- /dev/null +++ b/scoped_model/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/scoped_model/macos/Podfile b/scoped_model/macos/Podfile new file mode 100644 index 00000000..ff5ddb3b --- /dev/null +++ b/scoped_model/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/scoped_model/macos/Podfile.lock b/scoped_model/macos/Podfile.lock new file mode 100644 index 00000000..d2f9a639 --- /dev/null +++ b/scoped_model/macos/Podfile.lock @@ -0,0 +1,30 @@ +PODS: + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + +SPEC CHECKSUMS: + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.16.2 diff --git a/scoped_model/macos/Runner.xcodeproj/project.pbxproj b/scoped_model/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..50054181 --- /dev/null +++ b/scoped_model/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 744B7D8C46D8ED36F08B4ABA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3FCD22E2B9E588CE1F2E9DB /* Pods_Runner.framework */; }; + ABB0B26AAA39E2BE7D0B7A27 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE5C02D3D3E06D78BD7187AC /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* scoped_model_sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = scoped_model_sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 375EFE53CA3C5FB82BA4CEE4 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 432A1192BABCCB953AF09366 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 5145368E89E6CE5261889329 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + B593DA83DD802E2CC6DA1349 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + BE5C02D3D3E06D78BD7187AC /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C099E49D79F36967F5179A29 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + C3FCD22E2B9E588CE1F2E9DB /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F27C74B2C28C6A2AD930804A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ABB0B26AAA39E2BE7D0B7A27 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 744B7D8C46D8ED36F08B4ABA /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 797A9E0920CC9D3B49BCD691 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* scoped_model_sample.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 797A9E0920CC9D3B49BCD691 /* Pods */ = { + isa = PBXGroup; + children = ( + 432A1192BABCCB953AF09366 /* Pods-Runner.debug.xcconfig */, + B593DA83DD802E2CC6DA1349 /* Pods-Runner.release.xcconfig */, + F27C74B2C28C6A2AD930804A /* Pods-Runner.profile.xcconfig */, + 5145368E89E6CE5261889329 /* Pods-RunnerTests.debug.xcconfig */, + C099E49D79F36967F5179A29 /* Pods-RunnerTests.release.xcconfig */, + 375EFE53CA3C5FB82BA4CEE4 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C3FCD22E2B9E588CE1F2E9DB /* Pods_Runner.framework */, + BE5C02D3D3E06D78BD7187AC /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 7B05F39912D6DC948C95D785 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 27E3A124E26BEFBE126B2CD0 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 33607D807D1F2CBD04CFFD05 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* scoped_model_sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 27E3A124E26BEFBE126B2CD0 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 33607D807D1F2CBD04CFFD05 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 7B05F39912D6DC948C95D785 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5145368E89E6CE5261889329 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModelSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/scoped_model_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/scoped_model_sample"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C099E49D79F36967F5179A29 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModelSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/scoped_model_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/scoped_model_sample"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 375EFE53CA3C5FB82BA4CEE4 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModelSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/scoped_model_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/scoped_model_sample"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/scoped_model/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/scoped_model/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/scoped_model/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/scoped_model/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/scoped_model/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..39d69c0f --- /dev/null +++ b/scoped_model/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scoped_model/macos/Runner.xcworkspace/contents.xcworkspacedata b/scoped_model/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/scoped_model/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/scoped_model/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/scoped_model/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/scoped_model/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/scoped_model/macos/Runner/AppDelegate.swift b/scoped_model/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/scoped_model/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/scoped_model/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/scoped_model/macos/Runner/Base.lproj/MainMenu.xib b/scoped_model/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/scoped_model/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scoped_model/macos/Runner/Configs/AppInfo.xcconfig b/scoped_model/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..30fec302 --- /dev/null +++ b/scoped_model/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// 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 +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = scoped_model_sample + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.scopedModelSample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/scoped_model/macos/Runner/Configs/Debug.xcconfig b/scoped_model/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/scoped_model/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/scoped_model/macos/Runner/Configs/Release.xcconfig b/scoped_model/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/scoped_model/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/scoped_model/macos/Runner/Configs/Warnings.xcconfig b/scoped_model/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/scoped_model/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/scoped_model/macos/Runner/DebugProfile.entitlements b/scoped_model/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/scoped_model/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/scoped_model/macos/Runner/Info.plist b/scoped_model/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/scoped_model/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/scoped_model/macos/Runner/MainFlutterWindow.swift b/scoped_model/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/scoped_model/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/scoped_model/macos/Runner/Release.entitlements b/scoped_model/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/scoped_model/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/scoped_model/macos/RunnerTests/RunnerTests.swift b/scoped_model/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/scoped_model/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/scoped_model/pubspec.yaml b/scoped_model/pubspec.yaml index ffefa676..598fa99a 100644 --- a/scoped_model/pubspec.yaml +++ b/scoped_model/pubspec.yaml @@ -12,23 +12,30 @@ description: A new Flutter project. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html version: 1.0.0+1 +publish_to: none environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ^3.9.0 dependencies: + collection: flutter: sdk: flutter - scoped_model: ^1.0.1 - todos_repository_local_storage: - path: ../todos_repository_local_storage + path_provider: + scoped_model: + shared_preferences: todos_app_core: path: ../todos_app_core + todos_repository_core: + path: ../todos_repository_core + todos_repository_local_storage: + path: ../todos_repository_local_storage dev_dependencies: + flutter_lints: flutter_test: sdk: flutter - flutter_driver: + integration_test: sdk: flutter test: mockito: @@ -40,7 +47,6 @@ dev_dependencies: # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. diff --git a/scoped_model/test/app_state_test.dart b/scoped_model/test/app_state_test.dart index 53c6fb51..56a8729d 100644 --- a/scoped_model/test/app_state_test.dart +++ b/scoped_model/test/app_state_test.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:scoped_model_sample/models.dart'; @@ -13,11 +9,12 @@ void main() { group('TodoListModel', () { test('should check if there are completed todos', () async { final model = TodoListModel( - repository: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); + repository: MockRepository([ + Todo('a'), + Todo('b'), + Todo('c', complete: true), + ]), + ); await model.loadTodos(); expect(model.todos.any((it) => it.complete), true); @@ -25,11 +22,12 @@ void main() { test('should calculate the number of active todos', () async { final model = TodoListModel( - repository: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); + repository: MockRepository([ + Todo('a'), + Todo('b'), + Todo('c', complete: true), + ]), + ); await model.loadTodos(); expect(model.todos.where((it) => !it.complete).toList().length, 2); @@ -37,105 +35,81 @@ void main() { test('should calculate the number of completed todos', () async { final model = TodoListModel( - repository: MockRepository([ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ])); + repository: MockRepository([ + Todo('a'), + Todo('b'), + Todo('c', complete: true), + ]), + ); await model.loadTodos(); expect(model.todos.where((it) => it.complete).toList().length, 1); }); test('should return all todos if the VisibilityFilter is all', () async { - final todos = [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]; - final model = TodoListModel( - repository: MockRepository(todos), - activeFilter: VisibilityFilter.all); - await model.loadTodos(); - - expect(model.filteredTodos, todos); - }); - - test('should return active todos if the VisibilityFilter is active', - () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; + final todos = [Todo('a'), Todo('b'), Todo('c', complete: true)]; final model = TodoListModel( repository: MockRepository(todos), - activeFilter: VisibilityFilter.active, + activeFilter: VisibilityFilter.all, ); await model.loadTodos(); - expect(model.filteredTodos, [ - todo1, - todo2, - ]); + expect(model.filteredTodos, todos); }); - test('should return completed todos if the VisibilityFilter is completed', - () async { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final model = TodoListModel( - repository: MockRepository(todos), - activeFilter: VisibilityFilter.completed, - ); - await model.loadTodos(); + test( + 'should return active todos if the VisibilityFilter is active', + () async { + final todo1 = Todo('a'); + final todo2 = Todo('b'); + final todo3 = Todo('c', complete: true); + final todos = [todo1, todo2, todo3]; + final model = TodoListModel( + repository: MockRepository(todos), + activeFilter: VisibilityFilter.active, + ); + await model.loadTodos(); + + expect(model.filteredTodos, [todo1, todo2]); + }, + ); + + test( + 'should return completed todos if the VisibilityFilter is completed', + () async { + final todo1 = Todo('a'); + final todo2 = Todo('b'); + final todo3 = Todo('c', complete: true); + final todos = [todo1, todo2, todo3]; + final model = TodoListModel( + repository: MockRepository(todos), + activeFilter: VisibilityFilter.completed, + ); + await model.loadTodos(); - expect(model.filteredTodos, [todo3]); - }); + expect(model.filteredTodos, [todo3]); + }, + ); test('should clear the completed todos', () async { final todo1 = Todo('a'); final todo2 = Todo('b'); final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final model = TodoListModel( - repository: MockRepository(todos), - ); + final todos = [todo1, todo2, todo3]; + final model = TodoListModel(repository: MockRepository(todos)); await model.loadTodos(); model.clearCompleted(); - expect(model.todos, [ - todo1, - todo2, - ]); + expect(model.todos, [todo1, todo2]); }); test('toggle all as complete or incomplete', () async { final todo1 = Todo('a'); final todo2 = Todo('b'); final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final model = TodoListModel( - repository: MockRepository(todos), - ); + final todos = [todo1, todo2, todo3]; + final model = TodoListModel(repository: MockRepository(todos)); await model.loadTodos(); // Toggle all complete @@ -153,7 +127,7 @@ class MockRepository extends TodosRepository { List entities; MockRepository(List todos) - : entities = todos.map((it) => it.toEntity()).toList(); + : entities = todos.map((it) => it.toEntity()).toList(); @override Future> loadTodos() { @@ -161,7 +135,7 @@ class MockRepository extends TodosRepository { } @override - Future saveTodos(List todos) { + Future saveTodos(List todos) { return Future.sync(() => entities = todos); } } diff --git a/scoped_model/test_driver/integration_test.dart b/scoped_model/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/scoped_model/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/scoped_model/test_driver/todo_app.dart b/scoped_model/test_driver/todo_app.dart deleted file mode 100644 index c1ac2d2e..00000000 --- a/scoped_model/test_driver/todo_app.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// This line imports the extension -import 'package:flutter_driver/driver_extension.dart'; -import 'package:scoped_model_sample/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/scoped_model/test_driver/todo_app_test.dart b/scoped_model/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/scoped_model/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/scoped_model/web/favicon.png b/scoped_model/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/scoped_model/web/favicon.png differ diff --git a/scoped_model/web/icons/Icon-192.png b/scoped_model/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/scoped_model/web/icons/Icon-192.png differ diff --git a/scoped_model/web/icons/Icon-512.png b/scoped_model/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/scoped_model/web/icons/Icon-512.png differ diff --git a/scoped_model/web/icons/Icon-maskable-192.png b/scoped_model/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/scoped_model/web/icons/Icon-maskable-192.png differ diff --git a/scoped_model/web/icons/Icon-maskable-512.png b/scoped_model/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/scoped_model/web/icons/Icon-maskable-512.png differ diff --git a/scoped_model/web/index.html b/scoped_model/web/index.html new file mode 100644 index 00000000..2c929009 --- /dev/null +++ b/scoped_model/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + scoped_model_sample + + + + + + diff --git a/scoped_model/web/manifest.json b/scoped_model/web/manifest.json new file mode 100644 index 00000000..a576bb67 --- /dev/null +++ b/scoped_model/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "scoped_model_sample", + "short_name": "scoped_model_sample", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/scoped_model/windows/.gitignore b/scoped_model/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/scoped_model/windows/.gitignore @@ -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/ diff --git a/scoped_model/windows/CMakeLists.txt b/scoped_model/windows/CMakeLists.txt new file mode 100644 index 00000000..500ca1e3 --- /dev/null +++ b/scoped_model/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(scoped_model_sample 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 "scoped_model_sample") + +# 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) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_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 "$") +# 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) diff --git a/scoped_model/windows/flutter/CMakeLists.txt b/scoped_model/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/scoped_model/windows/flutter/CMakeLists.txt @@ -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} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/scoped_model/windows/flutter/generated_plugin_registrant.cc b/scoped_model/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/scoped_model/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/scoped_model/windows/flutter/generated_plugin_registrant.h b/scoped_model/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/scoped_model/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/scoped_model/windows/flutter/generated_plugins.cmake b/scoped_model/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/scoped_model/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +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 $) + 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) diff --git a/scoped_model/windows/runner/CMakeLists.txt b/scoped_model/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/scoped_model/windows/runner/CMakeLists.txt @@ -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) diff --git a/scoped_model/windows/runner/Runner.rc b/scoped_model/windows/runner/Runner.rc new file mode 100644 index 00000000..0b4f51f8 --- /dev/null +++ b/scoped_model/windows/runner/Runner.rc @@ -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", "com.example" "\0" + VALUE "FileDescription", "scoped_model_sample" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "scoped_model_sample" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "scoped_model_sample.exe" "\0" + VALUE "ProductName", "scoped_model_sample" "\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 diff --git a/scoped_model/windows/runner/flutter_window.cpp b/scoped_model/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/scoped_model/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#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( + 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 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); +} diff --git a/scoped_model/windows/runner/flutter_window.h b/scoped_model/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/scoped_model/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#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_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/scoped_model/windows/runner/main.cpp b/scoped_model/windows/runner/main.cpp new file mode 100644 index 00000000..f411910c --- /dev/null +++ b/scoped_model/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 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"scoped_model_sample", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/scoped_model/windows/runner/resource.h b/scoped_model/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/scoped_model/windows/runner/resource.h @@ -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 diff --git a/scoped_model/windows/runner/resources/app_icon.ico b/scoped_model/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/scoped_model/windows/runner/resources/app_icon.ico differ diff --git a/scoped_model/windows/runner/runner.exe.manifest b/scoped_model/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/scoped_model/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/scoped_model/windows/runner/utils.cpp b/scoped_model/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/scoped_model/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +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 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::vector 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; +} diff --git a/scoped_model/windows/runner/utils.h b/scoped_model/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/scoped_model/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// 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, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/scoped_model/windows/runner/win32_window.cpp b/scoped_model/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/scoped_model/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#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(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( + 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(origin.x), + static_cast(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(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(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(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( + 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)); + } +} diff --git a/scoped_model/windows/runner/win32_window.h b/scoped_model/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/scoped_model/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// 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_ diff --git a/scripts/android-wait-for-emulator.sh b/scripts/android-wait-for-emulator.sh deleted file mode 100755 index 4402fbfb..00000000 --- a/scripts/android-wait-for-emulator.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -# Originally written by Ralf Kistner , but placed in the public domain - -set +e - -bootanim="" -failcounter=0 -timeout_in_sec=360 - -until [[ "$bootanim" =~ "stopped" ]]; do - bootanim=`adb -e shell getprop init.svc.bootanim 2>&1 &` - if [[ "$bootanim" =~ "device not found" || "$bootanim" =~ "device offline" - || "$bootanim" =~ "running" ]]; then - let "failcounter += 1" - echo "Waiting for emulator to start: $failcounter of $timeout_in_sec : status: $bootanim" - if [[ $failcounter -gt timeout_in_sec ]]; then - echo "Timeout ($timeout_in_sec seconds) reached; failed to start emulator" - exit 1 - fi - fi - sleep 1 -done - -echo "Emulator is ready" \ No newline at end of file diff --git a/scripts/ci.sh b/scripts/ci.sh deleted file mode 100755 index fd3f5611..00000000 --- a/scripts/ci.sh +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env bash - -show_help() { - printf "\n\nusage: $0 [--get] [--analyze] [--ios] [--apk] [--driver] [--clean] [] - -Tool for managing CI builds. -(run from root of repo) - -where: - --get - get all dependencies - --analyze - analyze dart code for all packages - --ios - build ios release for all apps - --apk - build android release for all apps - --driver - run integration tests for all apps - (expects a single running emulator/simulator) - --clean - clean all builds - - run flutter driver for app at path -" - exit 1 -} - -# run integration tests -runDriver () { - cd $1 - if [ -f "lib/main.dart" ]; then - echo "Running integration tests in $1..." - flutter packages get - flutter driver test_driver/todo_app.dart - fi - exitCode=$? - cd - > /dev/null - return $exitCode -} - -# run function in all dirs -# expects a function name -allDirs() { - dirs=(`find . -maxdepth 2 -type d`) - for dir in "${dirs[@]}"; do - $1 $dir - done -} - -runGet() { - cd $1 - if [ -f "pubspec.yaml" ]; then - flutter packages get - fi - cd - > /dev/null -} - -runIos() { - cd $1; - if [ -f "lib/main.dart" ]; then - flutter build ios - fi - cd - > /dev/null -} - -runApk() { - cd $1; - if [ -f "lib/main.dart" ]; then - echo "build apk in $1" - flutter build apk - fi - cd - > /dev/null -} - -runClean() { - cd $1; - if [ -f "pubspec.yaml" ]; then - echo "run clean in $1" - flutter clean > /dev/null - rm -rf ios/Pods ios/Podfile.lock - rm -rf android/.gradle - rm -rf coverage - fi - cd - > /dev/null -} - -# if no arguments passed -if [ -z $1 ]; then show_help; fi - -if ! [ -d .git ]; then printf "\nError: not in root of repo"; show_help; fi - -case $1 in - --get) - allDirs "runGet" - ;; - --analyze) - flutter analyze - ;; - --ios) - allDirs "runIos" - ;; - --apk) - allDirs "runApk" - ;; - --driver) - allDirs "runDriver" - ;; - --clean) - allDirs "runClean" - ;; - *) - if [[ -d "$1" ]]; then - runDriver $1 - else - printf "\nError: not a directory: $1" - show_help - fi - ;; -esac diff --git a/scripts/line_counter.dart b/scripts/line_counter.dart deleted file mode 100644 index 99b7bac0..00000000 --- a/scripts/line_counter.dart +++ /dev/null @@ -1,109 +0,0 @@ -import 'dart:io'; - -class Sample { - final String name; - final List directories; - - Sample(this.name, List paths) - : directories = paths.map((path) => Directory('$path/lib')).toList(); -} - -class Output { - final String name; - final int lineCount; - - Output(this.name, this.lineCount); - - @override - String toString() { - return 'Output{name: $name, lineCount: $lineCount}'; - } -} - -void main() { - final samples = [ - Sample('change_notifier_provider', ['change_notifier_provider']), - Sample('bloc', ['bloc_flutter', 'blocs']), - Sample('bloc library', ['bloc_library']), - Sample('built_redux', ['built_redux']), - Sample('firestore_redux', ['firestore_redux']), - Sample('frideos_library', ['frideos_library']), - Sample('inherited_widget', ['inherited_widget']), - Sample('mobx', ['mobx']), - Sample('mvc', ['mvc']), - Sample('mvi', ['mvi_flutter', 'mvi_base']), - Sample('mvu', ['mvu']), - Sample('redux', ['redux']), - Sample('scoped_model', ['scoped_model']), - Sample('simple blocs', ['simple_bloc_flutter', 'simple_blocs']), - Sample('vanilla', ['vanilla']), - ]; - final outputs = samples.map((sample) { - return Output( - sample.name, - _countLines(sample.directories), - ); - }).toList(growable: false) - ..sort((a, b) => a.lineCount - b.lineCount); - - final strings = outputs - .map((output) => '| ${output.name} | ${output.lineCount} |') - .join('\n'); - - print(''' -# Line Counts - -Though not the only factor or even most important factor, the amount of code it -takes to achieve a working product is an important consideration when comparing -frameworks. - -This is an imperfect line count comparison -- some of the samples contain a bit -more functionality / are structured a bit differently than others -- and should -be taken with a grain of salt. All generated files, blank lines and comment -lines are removed for this comparison. - -For authors of frameworks or samples (hey, I'm one of those!): Please do not -take this comparison personally, nor should folks play "Code Golf" with the -samples to make them smaller, unless doing so improves the application overall. - -| *Sample* | *LOC (no comments)* | -|--------|-------------------| -$strings - -Note: This file was generated on ${DateTime.now().toUtc()} using `scripts/line_counter.dart`. -'''); -} - -int _countLines(List directories) { - final dartFiles = _findDartFiles(directories); - - return dartFiles.fold(0, (count, file) { - final nonCommentsLineCount = file - .readAsLinesSync() - .where((line) => !line.startsWith('//') && line.trim().isNotEmpty) - .length; - - return count + nonCommentsLineCount; - }); -} - -List _findDartFiles(List directories) { - final paths = directories.fold({}, (files, directory) { - final currentDirectoryDartFiles = directory - .listSync(recursive: true) - .whereType() - .map((file) => file.path) - .where((path) => - path.endsWith('.dart') && - !path.endsWith('.g.dart') && - !path.contains('todos_repository') && - !path.contains('file_storage') && - !path.contains('web_client') && - !path.contains('main_')) - .toSet(); - - return {...files, ...currentDirectoryDartFiles}; - }); - - return List.unmodifiable(paths.map((path) => File(path))); -} diff --git a/scripts/line_counter.sh b/scripts/line_counter.sh new file mode 100755 index 00000000..a6013663 --- /dev/null +++ b/scripts/line_counter.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +# Function to count lines in Dart files for a given directory +count_lines() { + local dir="$1" + local total_lines=0 + + # Find all .dart files recursively, excluding generated files and specific patterns + while IFS= read -r -d '' file; do + # Skip generated files and specific patterns + if [[ "$file" == *.g.dart ]] || \ + [[ "$file" == *todos_repository* ]] || \ + [[ "$file" == *file_storage* ]] || \ + [[ "$file" == *web_client* ]] || \ + [[ "$file" == *main_* ]]; then + continue + fi + + # Count non-comment, non-empty lines + local file_lines=$(grep -v '^[[:space:]]*//' "$file" | grep -v '^[[:space:]]*$' | wc -l) + total_lines=$((total_lines + file_lines)) + done < <(find "$dir/lib" -name "*.dart" -type f -print0 2>/dev/null) + + echo "$total_lines" +} + +# Function to count lines for multiple directories +count_lines_for_dirs() { + local total=0 + for dir in "$@"; do + if [ -d "$dir" ]; then + local lines=$(count_lines "$dir") + total=$((total + lines)) + fi + done + echo "$total" +} + +# Define samples as a single array of objects (name:dirs format) +samples=( + "change_notifier_provider:change_notifier_provider" + "bloc:bloc_flutter blocs" + "bloc library:bloc_library" + "built_redux:built_redux" + "firestore_redux:firestore_redux" + "inherited_widget:inherited_widget" + "mobx:mobx" + "mvi:mvi_flutter mvi_base" + "signals:signals" + "redux:redux" + "scoped_model:scoped_model" + "simple blocs:simple_bloc_flutter simple_blocs" + "vanilla:vanilla" +) + +# Collect results +results=() + +for sample in "${samples[@]}"; do + name=$(echo "$sample" | cut -d: -f1) + dirs=$(echo "$sample" | cut -d: -f2) + line_count=$(count_lines_for_dirs $dirs) + results+=("$line_count $name") +done + +# Sort results by line count +IFS=$'\n' sorted_results=($(sort -n <<<"${results[*]}")) +unset IFS + +# Generate output +echo "# Line Counts" +echo "" +echo "Though not the only factor or even most important factor, the amount of code it" +echo "takes to achieve a working product is an important consideration when comparing" +echo "frameworks." +echo "" +echo "This is an imperfect line count comparison -- some of the samples contain a bit" +echo "more functionality / are structured a bit differently than others -- and should" +echo "be taken with a grain of salt. All generated files, blank lines and comment" +echo "lines are removed for this comparison." +echo "" +echo "For authors of frameworks or samples (hey, I'm one of those!): Please do not" +echo "take this comparison personally, nor should folks play \"Code Golf\" with the" +echo "samples to make them smaller, unless doing so improves the application overall." +echo "" +echo "| *Sample* | *LOC (no comments)* |" +echo "|--------|-------------------|" + +# Output sorted results +for result in "${sorted_results[@]}"; do + line_count=$(echo "$result" | awk '{print $1}') + name=$(echo "$result" | awk '{for(i=2;i<=NF;i++) printf "%s ", $i; print ""}' | sed 's/ $//') + echo "| $name | $line_count |" +done + +echo "" +echo "Note: This file was generated on $(date -u) using \`scripts/line_counter.sh\`." diff --git a/scripts/runTests.sh b/scripts/runTests.sh deleted file mode 100755 index f4588d0b..00000000 --- a/scripts/runTests.sh +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/env bash - -# remember some failed commands and report on exit -error=false - -show_help() { - printf "usage: $0 [--help] [--report] [] - -Tool for running all unit and widget tests with code coverage. -(run from root of repo) - -where: - - run tests for package at path only - (otherwise runs all tests) - --report - run a coverage report - (requires lcov installed) - --help - print this message - -requires code_coverage package -(install with 'pub global activate coverage') -" - exit 1 -} - -# run unit and widget tests -runTests () { - local package_dir=$1 - local repo_dir=$2 - cd $package_dir; - if [[ -f "pubspec.yaml" ]] && [[ -d "test" ]]; then -# flutter packages get || echo "Ignore exit(1)" - flutter packages get - echo "run analyzer in $1" - flutter analyze - echo "run dartfmt in $1" - flutter dartfmt -n --set-exit-if-changed ./ - echo "running tests in $1" - # run tests with coverage - if grep flutter pubspec.yaml > /dev/null; then - echo "run flutter tests" - if [[ -f "test/all_tests.dart" ]]; then - flutter test --coverage test/all_tests.dart || error=true - else - flutter test --coverage || error=true - fi - else - # pure dart - echo "run dart tests" - pub get - pub run test || error=true - runDartTestsWithCoverage "test/all_tests.dart" || error=true - fi - combineCoverage $package_dir $repo_dir - fi - cd - > /dev/null -} - -# run tests with code coverage -runDartTestsWithCoverage () { - local test_path=$1 - local coverage_dir="coverage" - # clear coverage directory - rm -rf "$coverage_dir" - mkdir "$coverage_dir" - - OBS_PORT=9292 - - # Run the coverage collector to generate the JSON coverage report. - echo "Listening for coverage report on port $OBS_PORT..." - pub global run coverage:collect_coverage \ - --port=$OBS_PORT \ - --out="$coverage_dir"/coverage.json \ - --wait-paused \ - --resume-isolates & - - # Start tests in one VM. - echo "Running dart tests with code coverage..." - dart --disable-service-auth-codes \ - --enable-vm-service=$OBS_PORT \ - --pause-isolates-on-exit \ - "$test_path" - - echo "Generating LCOV report..." - pub global run coverage:format_coverage \ - --lcov \ - --in="$coverage_dir"/coverage.json \ - --out="$coverage_dir"/lcov.info \ - --packages=.packages \ - --report-on=lib -} - -# combine coverage into a single file for reporting -combineCoverage(){ - local package_dir=$1 - local repo_dir=$2 - escapedPath="$(echo $package_dir | sed 's/\//\\\//g')" - if [[ -d "coverage" ]]; then - # combine line coverage info from package tests to a common file - sed "s/^SF:lib/SF:$escapedPath\/lib/g" coverage/lcov.info >> $repo_dir/lcov.info - rm -rf "coverage" - fi -} - -runReport() { - if [[ -f "lcov.info" ]] && ! [[ "$TRAVIS" ]]; then - genhtml lcov.info -o coverage --no-function-coverage -s -p `pwd` - open coverage/index.html - fi -} - -if ! [[ -d .git ]]; then printf "\nError: not in root of repo"; show_help; fi - -case $1 in - --help) - show_help - ;; - --report) - if ! [[ -z ${2+x} ]]; then - printf "\nError: no extra parameters required: $2" - show_help - fi - runReport - ;; - *) - repo_dir=`pwd` - # if no parameter passed - if [[ -z $1 ]]; then - rm -f lcov.info - package_dirs=(`find . -maxdepth 2 -type d`) - for package_dir in "${package_dirs[@]}"; do - runTests $package_dir $repo_dir - done - else - if [[ -d "$1" ]]; then - runTests $1 $repo_dir - else - printf "\nError: not a directory: $1" - show_help - fi - fi - ;; -esac - -#Fail the build if there was an error -if [[ "$error" = true ]] ; -then - exit -1 -fi diff --git a/scripts/update_flutter.sh b/scripts/update_flutter.sh new file mode 100755 index 00000000..2da43113 --- /dev/null +++ b/scripts/update_flutter.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +# This script loops through subdirectories to find Flutter projects, +# cleans them by removing platform-specific folders, +# recreates the Flutter project files, and then removes an unnecessary test file. +# +# Usage: +# ./scripts/update_flutter.sh # Process all Flutter projects +# ./scripts/update_flutter.sh signals # Process only the 'signals' directory + +# Check if a specific directory was provided as an argument +if [ $# -eq 1 ]; then + # Process only the specified directory + target_dir="$1" + if [ ! -d "$target_dir" ]; then + echo "❌ Error: Directory '$target_dir' does not exist." + exit 1 + fi + # Add trailing slash if not present + if [[ ! "$target_dir" == */ ]]; then + target_dir="${target_dir}/" + fi + directories=("$target_dir") +else + # Find all directories one level deep from the current location + directories=(*/) +fi + +# Process the directories +for dir in "${directories[@]}"; do + # Ensure we are only processing actual directories. + if [ -d "$dir" ]; then + echo "🔎 Processing directory: $dir" + + pubspec_file="${dir}pubspec.yaml" + + # 1. Check if pubspec.yaml exists and contains a 'flutter:' dependency. + if [ -f "$pubspec_file" ] && grep -q "flutter:" "$pubspec_file"; then + echo "✅ Found pubspec.yaml with a Flutter dependency." + + # 2. Check if it's a valid project by looking for platform folders. + if [ -d "${dir}ios" ] || [ -d "${dir}android" ] || [ -d "${dir}web" ] || \ + [ -d "${dir}macos" ] || [ -d "${dir}windows" ] || [ -d "${dir}linux" ]; then + + echo "✅ Found platform folders. Proceeding with cleanup..." + + # Using a subshell to change directory, so we don't have to 'cd ..' + ( + cd "$dir" || exit + + # 3. Remove the old platform folders. + echo "Removing platform folders: ios, android, web, macos, windows, linux" + rm -rf ios android web macos windows linux + + # 4. Recreate the Flutter project in the current directory. + echo "🚀 Running 'fvm flutter create .'" + fvm flutter create . + + # 5. Remove the default widget test file. + widget_test_file="test/widget_test.dart" + if [ -f "$widget_test_file" ]; then + echo "🗑️ Removing generated file: $widget_test_file" + rm "$widget_test_file" + fi + + # Clean the project + echo "🧹 Cleaning the project" + fvm flutter clean + + # Install dependencies + echo "🔎 Installing dependencies" + fvm flutter pub get + + echo "✨ Successfully processed project in $dir" + ) + else + echo "⏭️ Skipping: No platform folders found." + fi + else + echo "⏭️ Skipping: Not a Flutter project." + fi + echo "--------------------------------------------------" + fi +done + +echo "All directories have been processed." diff --git a/signals/.gitignore b/signals/.gitignore new file mode 100644 index 00000000..3820a95c --- /dev/null +++ b/signals/.gitignore @@ -0,0 +1,45 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# 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 +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ +/coverage/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/signals/.metadata b/signals/.metadata new file mode 100644 index 00000000..05a8ab44 --- /dev/null +++ b/signals/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "05db9689081f091050f01aed79f04dce0c750154" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: android + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: ios + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: linux + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: macos + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: web + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: windows + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/signals/README.md b/signals/README.md new file mode 100644 index 00000000..b72900d9 --- /dev/null +++ b/signals/README.md @@ -0,0 +1,16 @@ +# signals + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/signals/analysis_options.yaml b/signals/analysis_options.yaml new file mode 100644 index 00000000..4549d270 --- /dev/null +++ b/signals/analysis_options.yaml @@ -0,0 +1,34 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# 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 +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + # The lint rules applied to this project can be customized in the + # 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 + # and their documentation is published at https://dart.dev/lints. + # + # 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 + # 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 + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/signals/android/.gitignore b/signals/android/.gitignore new file mode 100644 index 00000000..be3943c9 --- /dev/null +++ b/signals/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/signals/android/app/build.gradle.kts b/signals/android/app/build.gradle.kts new file mode 100644 index 00000000..2e71d7c1 --- /dev/null +++ b/signals/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.signals_sample" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.signals_sample" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/signals/android/app/src/debug/AndroidManifest.xml b/signals/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/signals/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/signals/android/app/src/main/AndroidManifest.xml b/signals/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..044a7e26 --- /dev/null +++ b/signals/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/signals/android/app/src/main/kotlin/com/example/signals_sample/MainActivity.kt b/signals/android/app/src/main/kotlin/com/example/signals_sample/MainActivity.kt new file mode 100644 index 00000000..a6c7100f --- /dev/null +++ b/signals/android/app/src/main/kotlin/com/example/signals_sample/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.signals_sample + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/signals/android/app/src/main/res/drawable-v21/launch_background.xml b/signals/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/signals/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/built_redux/android/app/src/main/res/drawable/launch_background.xml b/signals/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from built_redux/android/app/src/main/res/drawable/launch_background.xml rename to signals/android/app/src/main/res/drawable/launch_background.xml diff --git a/states_rebuilder/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/signals/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from states_rebuilder/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to signals/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/states_rebuilder/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/signals/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from states_rebuilder/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to signals/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/states_rebuilder/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/signals/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from states_rebuilder/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to signals/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/states_rebuilder/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/signals/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from states_rebuilder/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to signals/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/states_rebuilder/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/signals/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from states_rebuilder/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to signals/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/signals/android/app/src/main/res/values-night/styles.xml b/signals/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/signals/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/signals/android/app/src/main/res/values/styles.xml b/signals/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..cb1ef880 --- /dev/null +++ b/signals/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/signals/android/app/src/profile/AndroidManifest.xml b/signals/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/signals/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/signals/android/build.gradle.kts b/signals/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/signals/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/signals/android/gradle.properties b/signals/android/gradle.properties new file mode 100644 index 00000000..f018a618 --- /dev/null +++ b/signals/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/signals/android/gradle/wrapper/gradle-wrapper.properties b/signals/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..ac3b4792 --- /dev/null +++ b/signals/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/signals/android/settings.gradle.kts b/signals/android/settings.gradle.kts new file mode 100644 index 00000000..fb605bc8 --- /dev/null +++ b/signals/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/signals/integration_test/app_test.dart b/signals/integration_test/app_test.dart new file mode 100644 index 00000000..769ff580 --- /dev/null +++ b/signals/integration_test/app_test.dart @@ -0,0 +1,19 @@ +import 'package:integration_tests/integration_tests.dart' as integration_tests; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:signals_sample/app.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; + +void main() { + integration_tests.run( + appBuilder: () async { + return SignalsApp( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'mobx_test_${DateTime.now().toIso8601String()}', + await SharedPreferences.getInstance(), + ), + ), + ); + }, + ); +} diff --git a/signals/ios/.gitignore b/signals/ios/.gitignore new file mode 100644 index 00000000..7a7f9873 --- /dev/null +++ b/signals/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/signals/ios/Flutter/AppFrameworkInfo.plist b/signals/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..1dc6cf76 --- /dev/null +++ b/signals/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 13.0 + + diff --git a/signals/ios/Flutter/Debug.xcconfig b/signals/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..ec97fc6f --- /dev/null +++ b/signals/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/signals/ios/Flutter/Release.xcconfig b/signals/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..c4855bfe --- /dev/null +++ b/signals/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/signals/ios/Podfile b/signals/ios/Podfile new file mode 100644 index 00000000..620e46eb --- /dev/null +++ b/signals/ios/Podfile @@ -0,0 +1,43 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '13.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/signals/ios/Runner.xcodeproj/project.pbxproj b/signals/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..3b67d497 --- /dev/null +++ b/signals/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,619 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.signalsSample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.signalsSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.signalsSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.signalsSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.signalsSample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.signalsSample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/signals/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/signals/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/signals/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/signals/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/signals/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/signals/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/signals/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/signals/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/signals/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/signals/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/signals/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..e3773d42 --- /dev/null +++ b/signals/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/built_redux/ios/Runner.xcworkspace/contents.xcworkspacedata b/signals/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from built_redux/ios/Runner.xcworkspace/contents.xcworkspacedata rename to signals/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/signals/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/signals/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/signals/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/signals/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/signals/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/signals/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/signals/ios/Runner/AppDelegate.swift b/signals/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..62666446 --- /dev/null +++ b/signals/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 00000000..7353c41e Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 00000000..797d452e Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 00000000..6ed2d933 Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 00000000..4cd7b009 Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 00000000..fe730945 Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 00000000..321773cd Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 00000000..797d452e Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 00000000..502f463a Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 00000000..0ec30343 Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 00000000..0ec30343 Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 00000000..e9f5fea2 Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 00000000..84ac32ae Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 00000000..8953cba0 Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 00000000..0467bf12 Binary files /dev/null and b/signals/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/built_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/signals/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from built_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to signals/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/built_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/signals/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from built_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to signals/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/built_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/signals/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from built_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to signals/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/built_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/signals/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from built_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to signals/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/built_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/signals/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from built_redux/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to signals/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/built_redux/ios/Runner/Base.lproj/LaunchScreen.storyboard b/signals/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from built_redux/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to signals/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/built_redux/ios/Runner/Base.lproj/Main.storyboard b/signals/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from built_redux/ios/Runner/Base.lproj/Main.storyboard rename to signals/ios/Runner/Base.lproj/Main.storyboard diff --git a/signals/ios/Runner/Info.plist b/signals/ios/Runner/Info.plist new file mode 100644 index 00000000..215ca308 --- /dev/null +++ b/signals/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Signals Sample + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + signals_sample + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/states_rebuilder/ios/Runner/Runner-Bridging-Header.h b/signals/ios/Runner/Runner-Bridging-Header.h similarity index 100% rename from states_rebuilder/ios/Runner/Runner-Bridging-Header.h rename to signals/ios/Runner/Runner-Bridging-Header.h diff --git a/signals/ios/RunnerTests/RunnerTests.swift b/signals/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/signals/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/signals/lib/add_todo_screen.dart b/signals/lib/add_todo_screen.dart new file mode 100644 index 00000000..10b57781 --- /dev/null +++ b/signals/lib/add_todo_screen.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:todos_app_core/todos_app_core.dart'; + +import 'todo.dart'; + +class AddTodoScreen extends StatefulWidget { + const AddTodoScreen({ + super.key = ArchSampleKeys.addTodoScreen, + required this.onAdd, + }); + + final void Function(Todo) onAdd; + + @override + AddTodoScreenState createState() => AddTodoScreenState(); +} + +class AddTodoScreenState extends State { + final _formKey = GlobalKey(); + final _titleEditingController = TextEditingController(); + final _notesEditingController = TextEditingController(); + + @override + void dispose() { + _titleEditingController.dispose(); + _notesEditingController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final localizations = ArchSampleLocalizations.of(context); + final textTheme = Theme.of(context).textTheme; + + return Scaffold( + appBar: AppBar(title: Text(localizations.addTodo)), + body: Form( + key: _formKey, + autovalidateMode: AutovalidateMode.always, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + TextFormField( + key: ArchSampleKeys.taskField, + controller: _titleEditingController, + decoration: InputDecoration( + hintText: localizations.newTodoHint, + ), + style: textTheme.titleLarge, + autofocus: true, + validator: (val) { + return val == null || val.trim().isEmpty + ? localizations.emptyTodoError + : null; + }, + ), + TextFormField( + key: ArchSampleKeys.noteField, + controller: _notesEditingController, + style: textTheme.titleMedium, + decoration: InputDecoration(hintText: localizations.notesHint), + maxLines: 10, + ), + ], + ), + ), + ), + floatingActionButton: FloatingActionButton( + key: ArchSampleKeys.saveNewTodo, + tooltip: localizations.addTodo, + onPressed: () { + if (_formKey.currentState!.validate()) { + widget.onAdd( + Todo( + _titleEditingController.text, + note: _notesEditingController.text, + ), + ); + } + }, + child: const Icon(Icons.add), + ), + ); + } +} diff --git a/signals/lib/app.dart b/signals/lib/app.dart new file mode 100644 index 00000000..b6bc7fa5 --- /dev/null +++ b/signals/lib/app.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:signals_sample/todo_list_controller.dart'; +import 'package:todos_app_core/todos_app_core.dart'; +import 'package:todos_repository_core/todos_repository_core.dart'; + +import 'add_todo_screen.dart'; +import 'home/home_screen.dart'; +import 'localization.dart'; +import 'todo.dart'; + +class SignalsApp extends StatelessWidget { + final TodosRepository repository; + + const SignalsApp({super.key, required this.repository}); + + @override + Widget build(BuildContext context) { + return Provider( + create: (_) => TodoListController(repository: repository)..init(), + dispose: (_, controller) => controller.dispose(), + child: MaterialApp( + theme: ArchSampleTheme.lightTheme, + darkTheme: ArchSampleTheme.darkTheme, + localizationsDelegates: [ + ArchSampleLocalizationsDelegate(), + SignalsLocalizationsDelegate(), + ], + onGenerateTitle: (context) => SignalsLocalizations.of(context).appTitle, + routes: { + ArchSampleRoutes.home: (context) => HomeScreen(), + ArchSampleRoutes.addTodo: (context) => AddTodoScreen( + onAdd: (Todo todo) { + context.read().todos.add(todo); + + Navigator.pop(context); + }, + ), + }, + ), + ); + } +} diff --git a/signals/lib/details_screen.dart b/signals/lib/details_screen.dart new file mode 100644 index 00000000..432e59c4 --- /dev/null +++ b/signals/lib/details_screen.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; +import 'package:signals/signals_flutter.dart'; +import 'package:todos_app_core/todos_app_core.dart'; + +import 'edit_todo_screen.dart'; +import 'todo.dart'; + +class DetailsScreen extends StatelessWidget { + final Todo todo; + final void Function() onRemove; + + const DetailsScreen({required this.todo, required this.onRemove}) + : super(key: ArchSampleKeys.todoDetailsScreen); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(ArchSampleLocalizations.of(context).todoDetails), + actions: [ + IconButton( + key: ArchSampleKeys.deleteTodoButton, + tooltip: ArchSampleLocalizations.of(context).deleteTodo, + icon: const Icon(Icons.delete), + onPressed: onRemove, + ), + ], + ), + floatingActionButton: FloatingActionButton( + key: ArchSampleKeys.editTodoFab, + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => EditTodoScreen( + todo: todo, + onEdit: () => Navigator.pop(context), + ), + ), + ); + }, + child: const Icon(Icons.edit), + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: ListView( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Watch( + (_) => Checkbox( + key: ArchSampleKeys.detailsTodoItemCheckbox, + value: todo.complete.value, + onChanged: (done) => todo.complete.value = done ?? false, + ), + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(top: 8.0, bottom: 16.0), + child: Watch( + (context) => Text( + todo.task.value, + key: ArchSampleKeys.detailsTodoItemTask, + style: Theme.of(context).textTheme.headlineSmall, + ), + ), + ), + Watch( + (_) => Text( + todo.note.value, + key: ArchSampleKeys.detailsTodoItemNote, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ], + ), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/signals/lib/edit_todo_screen.dart b/signals/lib/edit_todo_screen.dart new file mode 100644 index 00000000..07750381 --- /dev/null +++ b/signals/lib/edit_todo_screen.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:signals_sample/todo.dart'; +import 'package:todos_app_core/todos_app_core.dart'; + +class EditTodoScreen extends StatefulWidget { + final void Function() onEdit; + final Todo todo; + + const EditTodoScreen({required this.todo, required this.onEdit}) + : super(key: ArchSampleKeys.editTodoScreen); + + @override + EditTodoScreenState createState() => EditTodoScreenState(); +} + +class EditTodoScreenState extends State { + final _formKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text(ArchSampleLocalizations.of(context).editTodo)), + body: Form( + key: _formKey, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + TextFormField( + key: ArchSampleKeys.taskField, + initialValue: widget.todo.task.value, + style: Theme.of(context).textTheme.headlineSmall, + decoration: InputDecoration( + hintText: ArchSampleLocalizations.of(context).newTodoHint, + ), + validator: (val) { + return val == null || val.trim().isEmpty + ? ArchSampleLocalizations.of(context).emptyTodoError + : null; + }, + onSaved: (value) => widget.todo.task.value = value ?? '', + ), + TextFormField( + key: ArchSampleKeys.noteField, + initialValue: widget.todo.note.value, + decoration: InputDecoration( + hintText: ArchSampleLocalizations.of(context).notesHint, + ), + maxLines: 10, + onSaved: (value) => widget.todo.note.value = value ?? '', + ), + ], + ), + ), + ), + floatingActionButton: FloatingActionButton( + key: ArchSampleKeys.saveTodoFab, + tooltip: ArchSampleLocalizations.of(context).saveChanges, + onPressed: () { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + widget.onEdit(); + } + }, + child: const Icon(Icons.check), + ), + ); + } +} diff --git a/signals/lib/home/extra_actions_button.dart b/signals/lib/home/extra_actions_button.dart new file mode 100644 index 00000000..c82d2bec --- /dev/null +++ b/signals/lib/home/extra_actions_button.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:todos_app_core/todos_app_core.dart'; + +import '../todo_list_controller.dart'; + +class ExtraActionsButton extends StatelessWidget { + const ExtraActionsButton({super.key}); + + @override + Widget build(BuildContext context) { + final controller = context.watch(); + + return PopupMenuButton( + key: ArchSampleKeys.extraActionsButton, + onSelected: (action) { + switch (action) { + case ExtraAction.toggleAllComplete: + controller.toggleAll(); + break; + case ExtraAction.clearCompleted: + controller.clearCompleted(); + break; + } + }, + itemBuilder: (BuildContext context) { + return >[ + PopupMenuItem( + key: ArchSampleKeys.toggleAll, + value: ExtraAction.toggleAllComplete, + child: Text( + controller.hasActiveTodos.value + ? ArchSampleLocalizations.of(context).markAllComplete + : ArchSampleLocalizations.of(context).markAllIncomplete, + ), + ), + PopupMenuItem( + key: ArchSampleKeys.clearCompleted, + value: ExtraAction.clearCompleted, + child: Text(ArchSampleLocalizations.of(context).clearCompleted), + ), + ]; + }, + ); + } +} + +enum ExtraAction { toggleAllComplete, clearCompleted } diff --git a/signals/lib/home/filter_button.dart b/signals/lib/home/filter_button.dart new file mode 100644 index 00000000..4ef52a97 --- /dev/null +++ b/signals/lib/home/filter_button.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:signals/signals_flutter.dart'; +import 'package:signals_sample/todo_list_controller.dart'; +import 'package:todos_app_core/todos_app_core.dart'; + +class FilterButton extends StatelessWidget { + final bool isActive; + + const FilterButton({super.key, required this.isActive}); + + @override + Widget build(BuildContext context) { + final controller = context.watch(); + + return IgnorePointer( + ignoring: !isActive, + child: AnimatedOpacity( + opacity: isActive ? 1.0 : 0.0, + duration: const Duration(milliseconds: 150), + child: Watch((context) { + return PopupMenuButton( + key: ArchSampleKeys.filterButton, + tooltip: ArchSampleLocalizations.of(context).filterTodos, + initialValue: controller.filter.value, + onSelected: (filter) => controller.filter.value = filter, + itemBuilder: (BuildContext context) => _items(context, controller), + icon: const Icon(Icons.filter_list), + ); + }), + ), + ); + } + + List> _items( + BuildContext context, + TodoListController controller, + ) { + final activeStyle = Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).colorScheme.secondary, + ); + final defaultStyle = Theme.of(context).textTheme.bodyMedium; + + return [ + PopupMenuItem( + key: ArchSampleKeys.allFilter, + value: VisibilityFilter.all, + child: Text( + ArchSampleLocalizations.of(context).showAll, + style: controller.filter.value == VisibilityFilter.all + ? activeStyle + : defaultStyle, + ), + ), + PopupMenuItem( + key: ArchSampleKeys.activeFilter, + value: VisibilityFilter.active, + child: Text( + ArchSampleLocalizations.of(context).showActive, + style: controller.filter.value == VisibilityFilter.active + ? activeStyle + : defaultStyle, + ), + ), + PopupMenuItem( + key: ArchSampleKeys.completedFilter, + value: VisibilityFilter.completed, + child: Text( + ArchSampleLocalizations.of(context).showCompleted, + style: controller.filter.value == VisibilityFilter.completed + ? activeStyle + : defaultStyle, + ), + ), + ]; + } +} diff --git a/signals/lib/home/home_screen.dart b/signals/lib/home/home_screen.dart new file mode 100644 index 00000000..448a29d7 --- /dev/null +++ b/signals/lib/home/home_screen.dart @@ -0,0 +1,127 @@ +import 'package:flutter/material.dart' hide Action; +import 'package:provider/provider.dart'; +import 'package:signals/signals_flutter.dart'; +import 'package:signals_sample/localization.dart'; +import 'package:signals_sample/todo_list_controller.dart'; +import 'package:todos_app_core/todos_app_core.dart'; + +import '../todo.dart'; +import 'extra_actions_button.dart'; +import 'filter_button.dart'; +import 'stats_view.dart'; +import 'todo_list_view.dart'; + +class HomeScreen extends StatefulWidget { + const HomeScreen({super.key}); + + @override + HomeScreenState createState() => HomeScreenState(); +} + +class HomeScreenState extends State { + // Because the state of the tabs is only a concern to the HomeScreen Widget, + // it is stored as local state rather than in the TodoListController. + final _tab = Signal(HomeScreenTab.todos); + + @override + Widget build(BuildContext context) { + final controller = context.watch(); + + return Scaffold( + appBar: AppBar( + title: Text(SignalsLocalizations.of(context).appTitle), + actions: [ + Watch( + (_) => FilterButton(isActive: _tab.value == HomeScreenTab.todos), + ), + const ExtraActionsButton(), + ], + ), + floatingActionButton: FloatingActionButton( + key: ArchSampleKeys.addTodoFab, + onPressed: () => Navigator.pushNamed(context, ArchSampleRoutes.addTodo), + tooltip: ArchSampleLocalizations.of(context).addTodo, + child: const Icon(Icons.add), + ), + body: FutureBuilder( + future: controller.initializingFuture, + builder: (context, snapshot) { + if (snapshot.connectionState != ConnectionState.done) { + return Center( + child: CircularProgressIndicator( + key: ArchSampleKeys.todosLoading, + ), + ); + } + + return Watch((context) { + switch (_tab.value) { + case HomeScreenTab.stats: + return const StatsView(); + case HomeScreenTab.todos: + return TodoListView( + onRemove: (context, todo) { + controller.todos.remove(todo); + _displayRemovalNotification(context, todo); + }, + ); + } + }); + }, + ), + bottomNavigationBar: Watch((context) { + return BottomNavigationBar( + key: ArchSampleKeys.tabs, + currentIndex: HomeScreenTab.values.indexOf(_tab.value), + onTap: (int index) { + _tab.value = HomeScreenTab.values[index]; + }, + items: [ + for (final tab in HomeScreenTab.values) + BottomNavigationBarItem( + icon: Icon(tab.icon, key: tab.key), + label: tab.title, + ), + ], + ); + }), + ); + } + + void _displayRemovalNotification(BuildContext context, Todo todo) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + key: ArchSampleKeys.snackbar, + duration: const Duration(seconds: 2), + content: Text( + ArchSampleLocalizations.of(context).todoDeleted(todo.task.value), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + action: SnackBarAction( + key: ArchSampleKeys.snackbarAction(todo.id.value), + label: ArchSampleLocalizations.of(context).undo, + onPressed: () => context.read().todos.add(todo), + ), + ), + ); + } +} + +enum HomeScreenTab { todos, stats } + +extension TabExtensions on HomeScreenTab { + IconData get icon { + return (this == HomeScreenTab.todos) ? Icons.list : Icons.show_chart; + } + + String get title { + return this == HomeScreenTab.todos ? 'Todos' : 'Stats'; + } + + Key get key { + return this == HomeScreenTab.stats + ? ArchSampleKeys.statsTab + : ArchSampleKeys.todoTab; + } +} diff --git a/signals/lib/home/stats_view.dart b/signals/lib/home/stats_view.dart new file mode 100644 index 00000000..0298c0dd --- /dev/null +++ b/signals/lib/home/stats_view.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:signals/signals_flutter.dart'; +import 'package:signals_sample/todo_list_controller.dart'; +import 'package:todos_app_core/todos_app_core.dart'; + +class StatsView extends StatelessWidget { + const StatsView({super.key}); + + @override + Widget build(BuildContext context) { + final controller = context.read(); + + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: Text( + ArchSampleLocalizations.of(context).completedTodos, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + Padding( + padding: const EdgeInsets.only(bottom: 24.0), + child: Watch( + (context) => Text( + '${controller.numCompleted}', + key: ArchSampleKeys.statsNumCompleted, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: Text( + ArchSampleLocalizations.of(context).activeTodos, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + Padding( + padding: const EdgeInsets.only(bottom: 24.0), + child: Watch( + (context) => Text( + '${controller.numActive}', + key: ArchSampleKeys.statsNumActive, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ), + ], + ), + ); + } +} diff --git a/signals/lib/home/todo_list_view.dart b/signals/lib/home/todo_list_view.dart new file mode 100644 index 00000000..cb346cf0 --- /dev/null +++ b/signals/lib/home/todo_list_view.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:signals/signals_flutter.dart'; +import 'package:signals_sample/todo_list_controller.dart'; +import 'package:todos_app_core/todos_app_core.dart'; + +import '../details_screen.dart'; +import '../todo.dart'; + +class TodoListView extends StatelessWidget { + final void Function(BuildContext context, Todo todo) onRemove; + + const TodoListView({super.key, required this.onRemove}); + + @override + Widget build(BuildContext context) { + return Watch((context) { + final todos = context.read().visibleTodos; + + return ListView.builder( + key: ArchSampleKeys.todoList, + itemCount: todos.value.length, + itemBuilder: (context, index) { + final todo = todos.value[index]; + + return Dismissible( + key: ArchSampleKeys.todoItem(todo.id.value), + onDismissed: (_) => onRemove(context, todo), + child: ListTile( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) { + return DetailsScreen( + todo: todo, + onRemove: () { + Navigator.pop(context); + onRemove(context, todo); + }, + ); + }, + ), + ); + }, + leading: Watch( + (_) => Checkbox( + key: ArchSampleKeys.todoItemCheckbox(todo.id.value), + value: todo.complete.value, + onChanged: (done) => todo.complete.value = done ?? false, + ), + ), + title: Watch( + (context) => Text( + todo.task.value, + key: ArchSampleKeys.todoItemTask(todo.id.value), + style: Theme.of(context).textTheme.titleLarge, + ), + ), + subtitle: Watch( + (_) => Text( + todo.note.value, + key: ArchSampleKeys.todoItemNote(todo.id.value), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ), + ); + }, + ); + }); + } +} diff --git a/signals/lib/localization.dart b/signals/lib/localization.dart new file mode 100644 index 00000000..cb462cd1 --- /dev/null +++ b/signals/lib/localization.dart @@ -0,0 +1,28 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +class SignalsLocalizations { + static SignalsLocalizations of(BuildContext context) { + return Localizations.of( + context, + SignalsLocalizations, + )!; + } + + String get appTitle => 'Signals Example'; +} + +class SignalsLocalizationsDelegate + extends LocalizationsDelegate { + @override + Future load(Locale locale) => + Future(() => SignalsLocalizations()); + + @override + bool shouldReload(SignalsLocalizationsDelegate old) => false; + + @override + bool isSupported(Locale locale) => + locale.languageCode.toLowerCase().contains('en'); +} diff --git a/signals/lib/main.dart b/signals/lib/main.dart new file mode 100644 index 00000000..b9df2867 --- /dev/null +++ b/signals/lib/main.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; + +import 'app.dart'; + +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + + runApp( + SignalsApp( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'mobx_todos', + await SharedPreferences.getInstance(), + ), + ), + ), + ); +} diff --git a/signals/lib/todo.dart b/signals/lib/todo.dart new file mode 100644 index 00000000..9a442f76 --- /dev/null +++ b/signals/lib/todo.dart @@ -0,0 +1,37 @@ +import 'package:signals/signals.dart'; +import 'package:todos_app_core/todos_app_core.dart'; + +class Todo { + final Signal complete; + final Signal id; + final Signal note; + final Signal task; + + Todo(String task, {bool complete = false, String note = '', String? id}) + : task = Signal(task), + complete = Signal(complete), + note = Signal(note), + id = Signal(id ?? Uuid().generateV4()); + + @override + int get hashCode => + complete.value.hashCode ^ + task.value.hashCode ^ + note.value.hashCode ^ + id.value.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Todo && + runtimeType == other.runtimeType && + complete.value == other.complete.value && + task.value == other.task.value && + note.value == other.note.value && + id.value == other.id.value; + + @override + String toString() { + return 'Todo{complete: ${complete.value}, task: ${task.value}, note: ${note.value}, id: ${id.value}}'; + } +} diff --git a/signals/lib/todo_codec.dart b/signals/lib/todo_codec.dart new file mode 100644 index 00000000..2226e43b --- /dev/null +++ b/signals/lib/todo_codec.dart @@ -0,0 +1,46 @@ +import 'dart:convert'; + +import 'package:todos_repository_core/todos_repository_core.dart'; + +import 'todo.dart'; + +// Converts Todos to TodoEntities and vice-versa for interop with the +// TodoRepository (data layer). Implements the standard `Codec` interface from +// dart:convert. +class TodoCodec extends Codec { + const TodoCodec(); + + @override + Converter get decoder => const _TodoDecoder(); + + @override + Converter get encoder => const _TodoEncoder(); +} + +class _TodoEncoder extends Converter { + const _TodoEncoder(); + + @override + TodoEntity convert(Todo todo) { + return TodoEntity( + todo.task.value, + todo.id.value, + todo.note.value, + todo.complete.value, + ); + } +} + +class _TodoDecoder extends Converter { + const _TodoDecoder(); + + @override + Todo convert(TodoEntity entity) { + return Todo( + entity.task, + complete: entity.complete, + note: entity.note, + id: entity.id, + ); + } +} diff --git a/signals/lib/todo_list_controller.dart b/signals/lib/todo_list_controller.dart new file mode 100644 index 00000000..7c1f2ead --- /dev/null +++ b/signals/lib/todo_list_controller.dart @@ -0,0 +1,87 @@ +import 'package:signals/signals.dart'; +import 'package:signals_sample/todo.dart'; +import 'package:signals_sample/todo_codec.dart'; +import 'package:todos_repository_core/todos_repository_core.dart'; + +enum VisibilityFilter { all, active, completed } + +class TodoListController { + TodoListController({ + required TodosRepository repository, + VisibilityFilter? filter, + TodoCodec? codec, + }) : _todosRepository = repository, + _todoCodec = codec ?? const TodoCodec(), + todos = ListSignal([]), + filter = Signal(filter ?? VisibilityFilter.all); + + final TodosRepository _todosRepository; + final TodoCodec _todoCodec; + final ListSignal todos; + final Signal filter; + + late final EffectCleanup _persistenceEffectCleanup; + late final Future initializingFuture; + + ReadonlySignal> get activeTodos => Computed( + () => todos.where((t) => !t.complete.value).toList(growable: false), + ); + + ReadonlySignal> get completedTodos => Computed( + () => todos.where((t) => t.complete.value).toList(growable: false), + ); + + ReadonlySignal get hasActiveTodos => + Computed(() => activeTodos.value.isNotEmpty); + + ReadonlySignal get numActive => Computed(() => activeTodos.value.length); + + ReadonlySignal get numCompleted => + Computed(() => completedTodos.value.length); + + ReadonlySignal> get visibleTodos => Computed( + () => switch (filter.value) { + VisibilityFilter.active => activeTodos.value, + VisibilityFilter.completed => completedTodos.value, + VisibilityFilter.all => todos, + }, + ); + + void toggleAll() { + final allComplete = todos.every((todo) => todo.complete.value); + + batch(() { + for (final todo in todos) { + todo.complete.value = !allComplete; + } + }); + } + + void clearCompleted() => todos.removeWhere((todo) => todo.complete.value); + + Future _loadTodos() async { + final entities = await _todosRepository.loadTodos(); + + todos.addAll(entities.map(_todoCodec.decode).toList()); + } + + Future init() async { + initializingFuture = _loadTodos(); + + await initializingFuture; + + // Use `effect` from signals.dart to observe the list of todos and persist + // them to the repository whenever a change occurs. + // + // Save operations are debounced by a configurable delay to prevent writing + // to the repository more often than necessary. In production, save + // operations are debounced by 500ms. In tests, they are not debounced to + // speed up test execution. + _persistenceEffectCleanup = effect(() async { + final toSave = todos.value.map(_todoCodec.encode).toList(growable: false); + await _todosRepository.saveTodos(toSave); + }); + } + + void dispose() => _persistenceEffectCleanup(); +} diff --git a/signals/linux/.gitignore b/signals/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/signals/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/signals/linux/CMakeLists.txt b/signals/linux/CMakeLists.txt new file mode 100644 index 00000000..2ba803bf --- /dev/null +++ b/signals/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +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 "signals_sample") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.signals_sample") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +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() + +# 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() + +# 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_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# 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 +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# 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() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +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) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/signals/linux/flutter/CMakeLists.txt b/signals/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/signals/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +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. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# 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/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter 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. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/signals/linux/flutter/generated_plugin_registrant.cc b/signals/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e71a16d2 --- /dev/null +++ b/signals/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/signals/linux/flutter/generated_plugin_registrant.h b/signals/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/signals/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/signals/linux/flutter/generated_plugins.cmake b/signals/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/signals/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + 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}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/signals/linux/runner/CMakeLists.txt b/signals/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/signals/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "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 +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/signals/linux/runner/main.cc b/signals/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/signals/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/signals/linux/runner/my_application.cc b/signals/linux/runner/my_application.cc new file mode 100644 index 00000000..aa2c8eca --- /dev/null +++ b/signals/linux/runner/my_application.cc @@ -0,0 +1,144 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView *view) +{ + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // 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 + // desktop). + // 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. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "signals_sample"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "signals_sample"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/signals/linux/runner/my_application.h b/signals/linux/runner/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/signals/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/signals/macos/.gitignore b/signals/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/signals/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/signals/macos/Flutter/Flutter-Debug.xcconfig b/signals/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/signals/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/signals/macos/Flutter/Flutter-Release.xcconfig b/signals/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/signals/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/signals/macos/Flutter/GeneratedPluginRegistrant.swift b/signals/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b8e2b22f --- /dev/null +++ b/signals/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/signals/macos/Podfile b/signals/macos/Podfile new file mode 100644 index 00000000..ff5ddb3b --- /dev/null +++ b/signals/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/signals/macos/Podfile.lock b/signals/macos/Podfile.lock new file mode 100644 index 00000000..d2f9a639 --- /dev/null +++ b/signals/macos/Podfile.lock @@ -0,0 +1,30 @@ +PODS: + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + +SPEC CHECKSUMS: + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.16.2 diff --git a/signals/macos/Runner.xcodeproj/project.pbxproj b/signals/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..98a46c0c --- /dev/null +++ b/signals/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 85BC6F05405E947FDEE22EBC /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9AF64CD5AC1BCF18FC6C138 /* Pods_RunnerTests.framework */; }; + B4BB21DE84F0C1954B31B7E8 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50733925DFBA2A1C3DDD3CFC /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0A10B43194ABA80F4290BC74 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 2C55AE5A292B7887B20D3BC2 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 31D1A2AABF7A2EC6656A23E3 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* signals_sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = signals_sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 50733925DFBA2A1C3DDD3CFC /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5CBC020B4C25B30A9E502772 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + B64C17EABD281F8213FBA7CA /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + F18A13CD91DADE6FBD7EDBA4 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + F9AF64CD5AC1BCF18FC6C138 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 85BC6F05405E947FDEE22EBC /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B4BB21DE84F0C1954B31B7E8 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 4795F38FDA247A6E7167F1F8 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* signals_sample.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 4795F38FDA247A6E7167F1F8 /* Pods */ = { + isa = PBXGroup; + children = ( + 2C55AE5A292B7887B20D3BC2 /* Pods-Runner.debug.xcconfig */, + 5CBC020B4C25B30A9E502772 /* Pods-Runner.release.xcconfig */, + 31D1A2AABF7A2EC6656A23E3 /* Pods-Runner.profile.xcconfig */, + F18A13CD91DADE6FBD7EDBA4 /* Pods-RunnerTests.debug.xcconfig */, + B64C17EABD281F8213FBA7CA /* Pods-RunnerTests.release.xcconfig */, + 0A10B43194ABA80F4290BC74 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 50733925DFBA2A1C3DDD3CFC /* Pods_Runner.framework */, + F9AF64CD5AC1BCF18FC6C138 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + E6B31848EDF0E59989349B4C /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + E26D25A60EF518BF1CF419B4 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 69F5CF9B6165BF2E4A6FA2D6 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* signals_sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 69F5CF9B6165BF2E4A6FA2D6 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + E26D25A60EF518BF1CF419B4 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + E6B31848EDF0E59989349B4C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F18A13CD91DADE6FBD7EDBA4 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.signalsSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/signals_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/signals_sample"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B64C17EABD281F8213FBA7CA /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.signalsSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/signals_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/signals_sample"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0A10B43194ABA80F4290BC74 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.signalsSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/signals_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/signals_sample"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/signals/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/signals/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/signals/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/signals/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/signals/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..68b72b97 --- /dev/null +++ b/signals/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/signals/macos/Runner.xcworkspace/contents.xcworkspacedata b/signals/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/signals/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/signals/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/signals/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/signals/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/signals/macos/Runner/AppDelegate.swift b/signals/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/signals/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/signals/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/signals/macos/Runner/Base.lproj/MainMenu.xib b/signals/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/signals/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/signals/macos/Runner/Configs/AppInfo.xcconfig b/signals/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..b0252eee --- /dev/null +++ b/signals/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// 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 +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = signals_sample + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.signalsSample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/signals/macos/Runner/Configs/Debug.xcconfig b/signals/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/signals/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/signals/macos/Runner/Configs/Release.xcconfig b/signals/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/signals/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/signals/macos/Runner/Configs/Warnings.xcconfig b/signals/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/signals/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/signals/macos/Runner/DebugProfile.entitlements b/signals/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/signals/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/signals/macos/Runner/Info.plist b/signals/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/signals/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/signals/macos/Runner/MainFlutterWindow.swift b/signals/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/signals/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/signals/macos/Runner/Release.entitlements b/signals/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/signals/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/signals/macos/RunnerTests/RunnerTests.swift b/signals/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/signals/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/signals/pubspec.yaml b/signals/pubspec.yaml new file mode 100644 index 00000000..f7cc8585 --- /dev/null +++ b/signals/pubspec.yaml @@ -0,0 +1,95 @@ +name: signals_sample +description: "A new Flutter project." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: ^3.9.0 + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + provider: + shared_preferences: + signals: + signals_flutter: + todos_repository_local_storage: + path: ../todos_repository_local_storage + todos_repository_core: + path: ../todos_repository_core + todos_app_core: + path: ../todos_app_core + +dev_dependencies: + flutter_lints: + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + test: + mockito: + integration_tests: + path: ../integration_tests + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/to/resolution-aware-images + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/to/asset-from-package + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/to/font-from-package diff --git a/signals/test/todo_list_controller_test.dart b/signals/test/todo_list_controller_test.dart new file mode 100644 index 00000000..9a88cebd --- /dev/null +++ b/signals/test/todo_list_controller_test.dart @@ -0,0 +1,245 @@ +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:signals_sample/todo.dart'; +import 'package:signals_sample/todo_list_controller.dart'; +import 'package:test/test.dart'; +import 'package:todos_repository_core/todos_repository_core.dart'; + +import 'todo_list_controller_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('$TodoListController', () { + test('should compute the number of completed todos', () async { + final repository = MockTodosRepository(); + final controller = TodoListController(repository: repository); + + when(repository.loadTodos()).thenAnswer( + (_) async => [ + TodoEntity('a', '1', '', false), + TodoEntity('b', '2', '', false), + TodoEntity('c', '3', '', true), + ], + ); + await controller.init(); + + expect(controller.numCompleted.value, 1); + }); + + test('should calculate the number of active todos', () async { + final repository = MockTodosRepository(); + final controller = TodoListController(repository: repository); + + when(repository.loadTodos()).thenAnswer( + (_) async => [ + TodoEntity('a', '1', '', false), + TodoEntity('b', '2', '', false), + TodoEntity('c', '3', '', true), + ], + ); + await controller.init(); + + expect(controller.hasActiveTodos.value, isTrue); + expect(controller.numActive.value, 2); + }); + + test('should return all todos if the VisibilityFilter is all', () async { + final repository = MockTodosRepository(); + final controller = TodoListController( + filter: VisibilityFilter.all, + repository: repository, + ); + + when(repository.loadTodos()).thenAnswer( + (_) async => [ + TodoEntity('a', '1', '', false), + TodoEntity('b', '2', '', false), + TodoEntity('c', '3', '', true), + ], + ); + + await controller.init(); + + expect(controller.visibleTodos.value, [ + Todo('a', id: '1'), + Todo('b', id: '2'), + Todo('c', id: '3', complete: true), + ]); + }); + + test( + 'should return active todos if the VisibilityFilter is active', + () async { + final repository = MockTodosRepository(); + final controller = TodoListController( + filter: VisibilityFilter.active, + repository: repository, + ); + + when(repository.loadTodos()).thenAnswer( + (_) async => [ + TodoEntity('a', '1', '', false), + TodoEntity('b', '2', '', false), + TodoEntity('c', '3', '', true), + ], + ); + await controller.init(); + + expect(controller.visibleTodos.value, [ + Todo('a', id: '1'), + Todo('b', id: '2'), + ]); + }, + ); + + test( + 'should return completed todos if the VisibilityFilter is completed', + () async { + final repository = MockTodosRepository(); + final controller = TodoListController( + filter: VisibilityFilter.completed, + repository: repository, + ); + + when(repository.loadTodos()).thenAnswer( + (_) async => [ + TodoEntity('a', '1', '', false), + TodoEntity('b', '2', '', false), + TodoEntity('c', '3', '', true), + ], + ); + await controller.init(); + + expect(controller.visibleTodos.value, [ + Todo('c', id: '3', complete: true), + ]); + }, + ); + + test('should clear the completed todos', () async { + final repository = MockTodosRepository(); + final controller = TodoListController(repository: repository); + + when(repository.loadTodos()).thenAnswer( + (_) async => [ + TodoEntity('a', '1', '', false), + TodoEntity('b', '2', '', false), + TodoEntity('c', '3', '', true), + ], + ); + + await controller.init(); + controller.clearCompleted(); + + expect(controller.todos.value, [Todo('a', id: '1'), Todo('b', id: '2')]); + verify( + repository.saveTodos([ + TodoEntity('a', '1', '', false), + TodoEntity('b', '2', '', false), + ]), + ); + }); + + test('toggle all as complete or incomplete', () async { + final repository = MockTodosRepository(); + final controller = TodoListController(repository: repository); + + when(repository.loadTodos()).thenAnswer( + (_) async => [ + TodoEntity('a', '1', '', false), + TodoEntity('b', '2', '', false), + TodoEntity('c', '3', '', true), + ], + ); + + await controller.init(); + + // Toggle all complete + controller.toggleAll(); + expect(controller.todos.every((t) => t.complete.value), isTrue); + verify( + repository.saveTodos([ + TodoEntity('a', '1', '', true), + TodoEntity('b', '2', '', true), + TodoEntity('c', '3', '', true), + ]), + ); + + // Toggle all incomplete + controller.toggleAll(); + expect(controller.todos.every((t) => !t.complete.value), isTrue); + verify( + repository.saveTodos([ + TodoEntity('a', '1', '', false), + TodoEntity('b', '2', '', false), + TodoEntity('c', '3', '', false), + ]), + ); + }); + + test('should add a todo', () async { + final repository = MockTodosRepository(); + final controller = TodoListController(repository: repository); + + when( + repository.loadTodos(), + ).thenAnswer((_) async => [TodoEntity('a', '1', '', false)]); + + await controller.init(); + controller.todos.add(Todo('b', id: '2')); + + expect(controller.todos, [Todo('a', id: '1'), Todo('b', id: '2')]); + verify( + repository.saveTodos([ + TodoEntity('a', '1', '', false), + TodoEntity('b', '2', '', false), + ]), + ); + }); + + test('should remove a todo', () async { + final repository = MockTodosRepository(); + final controller = TodoListController(repository: repository); + + when( + repository.loadTodos(), + ).thenAnswer((_) async => [TodoEntity('a', '1', '', false)]); + + await controller.init(); + + controller.todos.remove(Todo('a', id: '1')); + + expect(controller.todos.value, []); + verify(repository.saveTodos([])); + }); + + test('should update a todo', () async { + final repository = MockTodosRepository(); + final controller = TodoListController(repository: repository); + + when(repository.loadTodos()).thenAnswer( + (_) async => [ + TodoEntity('a', '1', '', false), + TodoEntity('b', '2', '', false), + TodoEntity('c', '3', '', true), + ], + ); + await controller.init(); + + controller.todos[1].complete.value = true; + + expect(controller.todos.value, [ + Todo('a', id: '1'), + Todo('b', id: '2', complete: true), + Todo('c', id: '3', complete: true), + ]); + verify( + repository.saveTodos([ + TodoEntity('a', '1', '', false), + TodoEntity('b', '2', '', true), + TodoEntity('c', '3', '', true), + ]), + ); + }); + }); +} diff --git a/signals/test/todo_list_controller_test.mocks.dart b/signals/test/todo_list_controller_test.mocks.dart new file mode 100644 index 00000000..7b5b3b17 --- /dev/null +++ b/signals/test/todo_list_controller_test.mocks.dart @@ -0,0 +1,51 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in signals_sample/test/todo_list_controller_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:todos_repository_core/src/todo_entity.dart' as _i4; +import 'package:todos_repository_core/src/todos_repository.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +/// A class which mocks [TodosRepository]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodosRepository extends _i1.Mock implements _i2.TodosRepository { + @override + _i3.Future> loadTodos() => + (super.noSuchMethod( + Invocation.method(#loadTodos, []), + returnValue: _i3.Future>.value( + <_i4.TodoEntity>[], + ), + returnValueForMissingStub: _i3.Future>.value( + <_i4.TodoEntity>[], + ), + ) + as _i3.Future>); + + @override + _i3.Future saveTodos(List<_i4.TodoEntity>? todos) => + (super.noSuchMethod( + Invocation.method(#saveTodos, [todos]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); +} diff --git a/signals/test_driver/integration_test.dart b/signals/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/signals/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/signals/web/favicon.png b/signals/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/signals/web/favicon.png differ diff --git a/signals/web/icons/Icon-192.png b/signals/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/signals/web/icons/Icon-192.png differ diff --git a/signals/web/icons/Icon-512.png b/signals/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/signals/web/icons/Icon-512.png differ diff --git a/signals/web/icons/Icon-maskable-192.png b/signals/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/signals/web/icons/Icon-maskable-192.png differ diff --git a/signals/web/icons/Icon-maskable-512.png b/signals/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/signals/web/icons/Icon-maskable-512.png differ diff --git a/signals/web/index.html b/signals/web/index.html new file mode 100644 index 00000000..33e7a91d --- /dev/null +++ b/signals/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + signals_sample + + + + + + diff --git a/signals/web/manifest.json b/signals/web/manifest.json new file mode 100644 index 00000000..f0df473e --- /dev/null +++ b/signals/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "signals_sample", + "short_name": "signals_sample", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/signals/windows/.gitignore b/signals/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/signals/windows/.gitignore @@ -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/ diff --git a/signals/windows/CMakeLists.txt b/signals/windows/CMakeLists.txt new file mode 100644 index 00000000..ea80d449 --- /dev/null +++ b/signals/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(signals_sample 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 "signals_sample") + +# 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) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_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 "$") +# 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) diff --git a/signals/windows/flutter/CMakeLists.txt b/signals/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/signals/windows/flutter/CMakeLists.txt @@ -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} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/signals/windows/flutter/generated_plugin_registrant.cc b/signals/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/signals/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/signals/windows/flutter/generated_plugin_registrant.h b/signals/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/signals/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/signals/windows/flutter/generated_plugins.cmake b/signals/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/signals/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +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 $) + 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) diff --git a/signals/windows/runner/CMakeLists.txt b/signals/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/signals/windows/runner/CMakeLists.txt @@ -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) diff --git a/signals/windows/runner/Runner.rc b/signals/windows/runner/Runner.rc new file mode 100644 index 00000000..8bcf8bb2 --- /dev/null +++ b/signals/windows/runner/Runner.rc @@ -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", "com.example" "\0" + VALUE "FileDescription", "signals_sample" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "signals_sample" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "signals_sample.exe" "\0" + VALUE "ProductName", "signals_sample" "\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 diff --git a/signals/windows/runner/flutter_window.cpp b/signals/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/signals/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#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( + 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 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); +} diff --git a/signals/windows/runner/flutter_window.h b/signals/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/signals/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#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_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/signals/windows/runner/main.cpp b/signals/windows/runner/main.cpp new file mode 100644 index 00000000..d6bb6e4e --- /dev/null +++ b/signals/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 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"signals_sample", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/signals/windows/runner/resource.h b/signals/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/signals/windows/runner/resource.h @@ -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 diff --git a/signals/windows/runner/resources/app_icon.ico b/signals/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/signals/windows/runner/resources/app_icon.ico differ diff --git a/signals/windows/runner/runner.exe.manifest b/signals/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/signals/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/signals/windows/runner/utils.cpp b/signals/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/signals/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +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 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::vector 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; +} diff --git a/signals/windows/runner/utils.h b/signals/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/signals/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// 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, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/signals/windows/runner/win32_window.cpp b/signals/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/signals/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#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(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( + 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(origin.x), + static_cast(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(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(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(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( + 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)); + } +} diff --git a/signals/windows/runner/win32_window.h b/signals/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/signals/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// 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_ diff --git a/simple_bloc_flutter/.metadata b/simple_bloc_flutter/.metadata index 1b5cec02..05a8ab44 100644 --- a/simple_bloc_flutter/.metadata +++ b/simple_bloc_flutter/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: 27321ebbad34b0a3fafe99fac037102196d655ff - channel: stable + revision: "05db9689081f091050f01aed79f04dce0c750154" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: android + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: ios + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: linux + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: macos + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: web + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: windows + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/simple_bloc_flutter/analysis_options.yaml b/simple_bloc_flutter/analysis_options.yaml new file mode 100644 index 00000000..134f2137 --- /dev/null +++ b/simple_bloc_flutter/analysis_options.yaml @@ -0,0 +1,34 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# 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 +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + # The lint rules applied to this project can be customized in the + # 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 + # and their documentation is published at https://dart.dev/lints. + # + # 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 + # 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 + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/simple_bloc_flutter/android/.gitignore b/simple_bloc_flutter/android/.gitignore index bc2100d8..be3943c9 100644 --- a/simple_bloc_flutter/android/.gitignore +++ b/simple_bloc_flutter/android/.gitignore @@ -5,3 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/simple_bloc_flutter/android/app/build.gradle b/simple_bloc_flutter/android/app/build.gradle deleted file mode 100644 index 3635ab33..00000000 --- a/simple_bloc_flutter/android/app/build.gradle +++ /dev/null @@ -1,68 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.simple_bloc_flutter" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - multiDexEnabled true - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/simple_bloc_flutter/android/app/build.gradle.kts b/simple_bloc_flutter/android/app/build.gradle.kts new file mode 100644 index 00000000..7d47ffe2 --- /dev/null +++ b/simple_bloc_flutter/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.simple_bloc_flutter_sample" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.simple_bloc_flutter_sample" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/simple_bloc_flutter/android/app/src/debug/AndroidManifest.xml b/simple_bloc_flutter/android/app/src/debug/AndroidManifest.xml index eb07cafb..399f6981 100644 --- a/simple_bloc_flutter/android/app/src/debug/AndroidManifest.xml +++ b/simple_bloc_flutter/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/simple_bloc_flutter/android/app/src/main/AndroidManifest.xml b/simple_bloc_flutter/android/app/src/main/AndroidManifest.xml index aa5858a1..3aaf4dae 100644 --- a/simple_bloc_flutter/android/app/src/main/AndroidManifest.xml +++ b/simple_bloc_flutter/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,25 @@ - - + + + @@ -27,4 +31,15 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + diff --git a/simple_bloc_flutter/android/app/src/main/kotlin/com/example/simple_bloc_flutter/MainActivity.kt b/simple_bloc_flutter/android/app/src/main/kotlin/com/example/simple_bloc_flutter/MainActivity.kt deleted file mode 100644 index 42d0a44d..00000000 --- a/simple_bloc_flutter/android/app/src/main/kotlin/com/example/simple_bloc_flutter/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.simple_bloc_flutter - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/simple_bloc_flutter/android/app/src/main/kotlin/com/example/simple_bloc_flutter_sample/MainActivity.kt b/simple_bloc_flutter/android/app/src/main/kotlin/com/example/simple_bloc_flutter_sample/MainActivity.kt new file mode 100644 index 00000000..48e54521 --- /dev/null +++ b/simple_bloc_flutter/android/app/src/main/kotlin/com/example/simple_bloc_flutter_sample/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.simple_bloc_flutter_sample + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/simple_bloc_flutter/android/app/src/main/res/drawable-v21/launch_background.xml b/simple_bloc_flutter/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/simple_bloc_flutter/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/simple_bloc_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/simple_bloc_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index a3f285f9..db77bb4b 100644 Binary files a/simple_bloc_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/simple_bloc_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/simple_bloc_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/simple_bloc_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 5e6f3ac6..17987b79 100644 Binary files a/simple_bloc_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/simple_bloc_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/simple_bloc_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/simple_bloc_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 144d60be..09d43914 100644 Binary files a/simple_bloc_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/simple_bloc_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/simple_bloc_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/simple_bloc_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index deafae2d..d5f1c8d3 100644 Binary files a/simple_bloc_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/simple_bloc_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/simple_bloc_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/simple_bloc_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index d5614ac8..4d6372ee 100644 Binary files a/simple_bloc_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/simple_bloc_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/simple_bloc_flutter/android/app/src/main/res/values-night/styles.xml b/simple_bloc_flutter/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/simple_bloc_flutter/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/simple_bloc_flutter/android/app/src/main/res/values/styles.xml b/simple_bloc_flutter/android/app/src/main/res/values/styles.xml index 00fa4417..cb1ef880 100644 --- a/simple_bloc_flutter/android/app/src/main/res/values/styles.xml +++ b/simple_bloc_flutter/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ - + + diff --git a/simple_bloc_flutter/android/app/src/profile/AndroidManifest.xml b/simple_bloc_flutter/android/app/src/profile/AndroidManifest.xml index eb07cafb..399f6981 100644 --- a/simple_bloc_flutter/android/app/src/profile/AndroidManifest.xml +++ b/simple_bloc_flutter/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/simple_bloc_flutter/android/build.gradle b/simple_bloc_flutter/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/simple_bloc_flutter/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/simple_bloc_flutter/android/build.gradle.kts b/simple_bloc_flutter/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/simple_bloc_flutter/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/simple_bloc_flutter/android/gradle.properties b/simple_bloc_flutter/android/gradle.properties index 38c8d454..f018a618 100644 --- a/simple_bloc_flutter/android/gradle.properties +++ b/simple_bloc_flutter/android/gradle.properties @@ -1,4 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/simple_bloc_flutter/android/gradle/wrapper/gradle-wrapper.properties b/simple_bloc_flutter/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..ac3b4792 100644 --- a/simple_bloc_flutter/android/gradle/wrapper/gradle-wrapper.properties +++ b/simple_bloc_flutter/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/simple_bloc_flutter/android/settings.gradle b/simple_bloc_flutter/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/simple_bloc_flutter/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/simple_bloc_flutter/android/settings.gradle.kts b/simple_bloc_flutter/android/settings.gradle.kts new file mode 100644 index 00000000..fb605bc8 --- /dev/null +++ b/simple_bloc_flutter/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/simple_bloc_flutter/integration_test/app_test.dart b/simple_bloc_flutter/integration_test/app_test.dart new file mode 100644 index 00000000..28b4e648 --- /dev/null +++ b/simple_bloc_flutter/integration_test/app_test.dart @@ -0,0 +1,26 @@ +import 'package:integration_tests/integration_tests.dart' as integration_tests; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:simple_bloc_flutter_sample/anonymous_user_repository.dart'; +import 'package:simple_bloc_flutter_sample/app.dart'; +import 'package:simple_blocs/simple_blocs.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; + +void main() { + integration_tests.run( + appBuilder: () async { + return SimpleBlocApp( + todosInteractor: TodosInteractor( + ReactiveLocalStorageRepository( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'simple_bloc_test_${DateTime.now().toIso8601String()}', + await SharedPreferences.getInstance(), + ), + ), + ), + ), + userRepository: AnonymousUserRepository(), + ); + }, + ); +} diff --git a/simple_bloc_flutter/ios/.gitignore b/simple_bloc_flutter/ios/.gitignore index e96ef602..7a7f9873 100644 --- a/simple_bloc_flutter/ios/.gitignore +++ b/simple_bloc_flutter/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/simple_bloc_flutter/ios/Flutter/AppFrameworkInfo.plist b/simple_bloc_flutter/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f78..1dc6cf76 100644 --- a/simple_bloc_flutter/ios/Flutter/AppFrameworkInfo.plist +++ b/simple_bloc_flutter/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 13.0 diff --git a/simple_bloc_flutter/ios/Flutter/Debug.xcconfig b/simple_bloc_flutter/ios/Flutter/Debug.xcconfig index e8efba11..ec97fc6f 100644 --- a/simple_bloc_flutter/ios/Flutter/Debug.xcconfig +++ b/simple_bloc_flutter/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/simple_bloc_flutter/ios/Flutter/Release.xcconfig b/simple_bloc_flutter/ios/Flutter/Release.xcconfig index 399e9340..c4855bfe 100644 --- a/simple_bloc_flutter/ios/Flutter/Release.xcconfig +++ b/simple_bloc_flutter/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/simple_bloc_flutter/ios/Podfile b/simple_bloc_flutter/ios/Podfile index b30a428b..620e46eb 100644 --- a/simple_bloc_flutter/ios/Podfile +++ b/simple_bloc_flutter/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -10,81 +10,34 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - generated_key_values + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' +flutter_ios_podfile_setup - # Plugin Pods +target 'Runner' do + use_frameworks! - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths end end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/simple_bloc_flutter/ios/Runner.xcodeproj/project.pbxproj b/simple_bloc_flutter/ios/Runner.xcodeproj/project.pbxproj index 8acc15e9..71d5b573 100644 --- a/simple_bloc_flutter/ios/Runner.xcodeproj/project.pbxproj +++ b/simple_bloc_flutter/ios/Runner.xcodeproj/project.pbxproj @@ -3,23 +3,29 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 4EEE3E9523C494310065A5A2 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4EEE3E9423C494310065A5A2 /* GoogleService-Info.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -27,8 +33,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -38,15 +42,14 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 4EEE3E9423C494310065A5A2 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -59,20 +62,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -86,6 +93,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -93,6 +101,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -100,12 +109,10 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( - 4EEE3E9423C494310065A5A2 /* GoogleService-Info.plist */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -114,16 +121,26 @@ path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; @@ -150,9 +167,14 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -160,7 +182,7 @@ }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -173,18 +195,25 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 4EEE3E9523C494310065A5A2 /* GoogleService-Info.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); @@ -195,20 +224,23 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -224,6 +256,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -235,6 +275,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -257,9 +305,9 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -289,6 +337,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -297,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -313,18 +362,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutter; + PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutterSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -332,11 +377,58 @@ }; name = Profile; }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -366,6 +458,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -380,7 +473,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -390,9 +483,9 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -422,6 +515,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -430,11 +524,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -447,18 +542,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutter; + PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutterSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -474,18 +565,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutter; + PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutterSample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -496,6 +583,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/simple_bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/simple_bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/simple_bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/simple_bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/simple_bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/simple_bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/simple_bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/simple_bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/simple_bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/simple_bloc_flutter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/simple_bloc_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/simple_bloc_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..e3773d42 100644 --- a/simple_bloc_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/simple_bloc_flutter/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + + + + + @@ -61,8 +73,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - + + + + IDEDidComputeMac32BitWarning + + + diff --git a/simple_bloc_flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/simple_bloc_flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/simple_bloc_flutter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/simple_bloc_flutter/ios/Runner/AppDelegate.swift b/simple_bloc_flutter/ios/Runner/AppDelegate.swift index 70693e4a..62666446 100644 --- a/simple_bloc_flutter/ios/Runner/AppDelegate.swift +++ b/simple_bloc_flutter/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ -import UIKit import Flutter +import UIKit -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d22f10b2..d36b1fab 100644 --- a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -107,6 +107,12 @@ "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" } ], "info" : { diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 980e5ad6..7353c41e 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index fd870289..797d452e 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 75e84cd1..6ed2d933 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 03ab8a84..4cd7b009 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index a03431cb..fe730945 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index f47613ee..321773cd 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 7f2230a9..797d452e 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 42315c6d..502f463a 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index f9882cc0..0ec30343 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 45537513..0ec30343 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 6360ea17..e9f5fea2 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 152d5e12..84ac32ae 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 310b0b8f..8953cba0 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 092b7bfe..0467bf12 100644 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/simple_bloc_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/simple_bloc_flutter/ios/Runner/GoogleService-Info.plist b/simple_bloc_flutter/ios/Runner/GoogleService-Info.plist deleted file mode 100644 index c8cc9bf9..00000000 --- a/simple_bloc_flutter/ios/Runner/GoogleService-Info.plist +++ /dev/null @@ -1,40 +0,0 @@ - - - - - AD_UNIT_ID_FOR_BANNER_TEST - ca-app-pub-9999999999999999/9999999999 - AD_UNIT_ID_FOR_INTERSTITIAL_TEST - ca-app-pub-9999999999999999/9999999999 - CLIENT_ID - xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com - REVERSED_CLIENT_ID - com.googleusercontent.apps.xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - API_KEY - xxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx - GCM_SENDER_ID - 999999999999 - PLIST_VERSION - 1 - BUNDLE_ID - com.fluttersamples.bloc - PROJECT_ID - xxxxxxxxxxxxx-99999 - STORAGE_BUCKET - xxxxxxxxxxxxx-99999.appspot.com - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 9:999999999999:ios:xxxxxxxxxxxxxxxx - DATABASE_URL - https://xxxxxxxxxxxxx-99999.firebaseio.com - - \ No newline at end of file diff --git a/simple_bloc_flutter/ios/Runner/Info.plist b/simple_bloc_flutter/ios/Runner/Info.plist index 4094e090..6049340d 100644 --- a/simple_bloc_flutter/ios/Runner/Info.plist +++ b/simple_bloc_flutter/ios/Runner/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Simple Bloc Flutter Sample CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -11,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - simple_bloc_flutter + simple_bloc_flutter_sample CFBundlePackageType APPL CFBundleShortVersionString @@ -39,7 +41,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/simple_bloc_flutter/ios/Runner/Runner-Bridging-Header.h b/simple_bloc_flutter/ios/Runner/Runner-Bridging-Header.h index 7335fdf9..308a2a56 100644 --- a/simple_bloc_flutter/ios/Runner/Runner-Bridging-Header.h +++ b/simple_bloc_flutter/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file +#import "GeneratedPluginRegistrant.h" diff --git a/simple_bloc_flutter/ios/RunnerTests/RunnerTests.swift b/simple_bloc_flutter/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/simple_bloc_flutter/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/simple_bloc_flutter/lib/anonymous_user_repository.dart b/simple_bloc_flutter/lib/anonymous_user_repository.dart new file mode 100644 index 00000000..efd978f5 --- /dev/null +++ b/simple_bloc_flutter/lib/anonymous_user_repository.dart @@ -0,0 +1,7 @@ +import 'package:todos_repository_core/todos_repository_core.dart'; + +class AnonymousUserRepository implements UserRepository { + @override + Future login() async => + UserEntity(id: 'anonymous', displayName: '', photoUrl: ''); +} diff --git a/simple_bloc_flutter/lib/app.dart b/simple_bloc_flutter/lib/app.dart index 127bfba9..da4b2a98 100644 --- a/simple_bloc_flutter/lib/app.dart +++ b/simple_bloc_flutter/lib/app.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:simple_bloc_flutter_sample/dependency_injection.dart'; import 'package:simple_bloc_flutter_sample/localization.dart'; @@ -17,10 +13,10 @@ class SimpleBlocApp extends StatelessWidget { final UserRepository userRepository; const SimpleBlocApp({ - Key key, - this.todosInteractor, - this.userRepository, - }) : super(key: key); + super.key, + required this.todosInteractor, + required this.userRepository, + }); @override Widget build(BuildContext context) { @@ -30,17 +26,17 @@ class SimpleBlocApp extends StatelessWidget { child: TodosBlocProvider( bloc: TodosListBloc(todosInteractor), child: MaterialApp( - onGenerateTitle: (context) => BlocLocalizations.of(context).appTitle, - theme: ArchSampleTheme.theme, + onGenerateTitle: (context) => + SimpleBlocLocalizations.of(context).appTitle, + theme: ArchSampleTheme.lightTheme, + darkTheme: ArchSampleTheme.darkTheme, localizationsDelegates: [ ArchSampleLocalizationsDelegate(), - InheritedWidgetLocalizationsDelegate(), + SimpleBlocLocalizationsDelegate(), ], routes: { ArchSampleRoutes.home: (context) { - return HomeScreen( - repository: Injector.of(context).userRepository, - ); + return HomeScreen(); }, ArchSampleRoutes.addTodo: (context) { return AddEditScreen( diff --git a/simple_bloc_flutter/lib/dependency_injection.dart b/simple_bloc_flutter/lib/dependency_injection.dart index efb8f974..f7e911af 100644 --- a/simple_bloc_flutter/lib/dependency_injection.dart +++ b/simple_bloc_flutter/lib/dependency_injection.dart @@ -1,13 +1,6 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// A poor man's DI. This should be replaced by a proper solution once they -// are more stable. -library dependency_injector; - +// A poor man's DI, but an example of how to use the InheritedWidget class for +// DI in a Flutter app. import 'package:flutter/widgets.dart'; -import 'package:meta/meta.dart'; import 'package:simple_blocs/simple_blocs.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -15,15 +8,15 @@ class Injector extends InheritedWidget { final TodosInteractor todosInteractor; final UserRepository userRepository; - Injector({ - Key key, - @required this.todosInteractor, - @required this.userRepository, - @required Widget child, - }) : super(key: key, child: child); + const Injector({ + super.key, + required this.todosInteractor, + required this.userRepository, + required super.child, + }); static Injector of(BuildContext context) => - context.dependOnInheritedWidgetOfExactType(); + context.dependOnInheritedWidgetOfExactType()!; @override bool updateShouldNotify(Injector oldWidget) => diff --git a/simple_bloc_flutter/lib/localization.dart b/simple_bloc_flutter/lib/localization.dart index 855211d0..b1658f40 100644 --- a/simple_bloc_flutter/lib/localization.dart +++ b/simple_bloc_flutter/lib/localization.dart @@ -1,27 +1,26 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; -class BlocLocalizations { - static BlocLocalizations of(BuildContext context) { - return Localizations.of(context, BlocLocalizations); +class SimpleBlocLocalizations { + static SimpleBlocLocalizations of(BuildContext context) { + return Localizations.of( + context, + SimpleBlocLocalizations, + )!; } String get appTitle => 'Simple Bloc Example'; } -class InheritedWidgetLocalizationsDelegate - extends LocalizationsDelegate { +class SimpleBlocLocalizationsDelegate + extends LocalizationsDelegate { @override - Future load(Locale locale) => - Future(() => BlocLocalizations()); + Future load(Locale locale) => + Future(() => SimpleBlocLocalizations()); @override - bool shouldReload(InheritedWidgetLocalizationsDelegate old) => false; + bool shouldReload(SimpleBlocLocalizationsDelegate old) => false; @override bool isSupported(Locale locale) => diff --git a/simple_bloc_flutter/lib/main.dart b/simple_bloc_flutter/lib/main.dart index 722f66da..88e3a622 100644 --- a/simple_bloc_flutter/lib/main.dart +++ b/simple_bloc_flutter/lib/main.dart @@ -1,38 +1,28 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/widgets.dart'; -import 'package:key_value_store_flutter/key_value_store_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:simple_bloc_flutter_sample/anonymous_user_repository.dart'; import 'package:simple_bloc_flutter_sample/app.dart'; import 'package:simple_blocs/simple_blocs.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(SimpleBlocApp( - todosInteractor: TodosInteractor( - ReactiveLocalStorageRepository( - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'simple_bloc', - FlutterKeyValueStore(await SharedPreferences.getInstance()), + runApp( + SimpleBlocApp( + todosInteractor: TodosInteractor( + ReactiveLocalStorageRepository( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'simple_bloc', + await SharedPreferences.getInstance(), + ), ), ), ), + userRepository: AnonymousUserRepository(), ), - userRepository: AnonymousUserRepository(), - )); -} - -class AnonymousUserRepository implements UserRepository { - @override - Future login() { - return Future.value(UserEntity(id: 'anonymous')); - } + ); } diff --git a/simple_bloc_flutter/lib/main_firebase.dart b/simple_bloc_flutter/lib/main_firebase.dart deleted file mode 100644 index 76562476..00000000 --- a/simple_bloc_flutter/lib/main_firebase.dart +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:firebase_flutter_repository/reactive_todos_repository.dart'; -import 'package:firebase_flutter_repository/user_repository.dart'; -import 'package:flutter/widgets.dart'; -import 'package:simple_bloc_flutter_sample/app.dart'; -import 'package:simple_blocs/simple_blocs.dart'; - -void main() { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(SimpleBlocApp( - todosInteractor: TodosInteractor( - FirestoreReactiveTodosRepository(Firestore.instance), - ), - userRepository: FirebaseUserRepository(FirebaseAuth.instance), - )); -} diff --git a/simple_bloc_flutter/lib/main_web.dart b/simple_bloc_flutter/lib/main_web.dart deleted file mode 100644 index 079f68f6..00000000 --- a/simple_bloc_flutter/lib/main_web.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; -import 'dart:html'; - -import 'package:flutter/widgets.dart'; -import 'package:key_value_store_web/key_value_store_web.dart'; -import 'package:simple_bloc_flutter_sample/app.dart'; -import 'package:simple_blocs/simple_blocs.dart'; -import 'package:todos_repository_core/todos_repository_core.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - runApp(SimpleBlocApp( - todosInteractor: TodosInteractor( - ReactiveLocalStorageRepository( - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'simple_bloc', - WebKeyValueStore(window.localStorage), - ), - ), - ), - ), - userRepository: AnonymousUserRepository(), - )); -} - -class AnonymousUserRepository implements UserRepository { - @override - Future login() { - return Future.value(UserEntity(id: 'anonymous')); - } -} diff --git a/simple_bloc_flutter/lib/screens/add_edit_screen.dart b/simple_bloc_flutter/lib/screens/add_edit_screen.dart index c73ddaae..57d15645 100644 --- a/simple_bloc_flutter/lib/screens/add_edit_screen.dart +++ b/simple_bloc_flutter/lib/screens/add_edit_screen.dart @@ -1,34 +1,28 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:simple_blocs/simple_blocs.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class AddEditScreen extends StatefulWidget { - final Todo todo; - final Function(Todo) addTodo; - final Function(Todo) updateTodo; + final Todo? todo; + final void Function(Todo)? addTodo; + final void Function(Todo)? updateTodo; - AddEditScreen({ - Key key, - this.todo, + const AddEditScreen({ + super.key = ArchSampleKeys.addTodoScreen, this.addTodo, this.updateTodo, - }) : super(key: key ?? ArchSampleKeys.addTodoScreen); + this.todo, + }); @override - _AddEditScreenState createState() => _AddEditScreenState(); + AddEditScreenState createState() => AddEditScreenState(); } -class _AddEditScreenState extends State { +class AddEditScreenState extends State { static final GlobalKey formKey = GlobalKey(); - String _task; - String _note; + late String _task; + late String _note; @override Widget build(BuildContext context) { @@ -44,58 +38,55 @@ class _AddEditScreenState extends State { padding: EdgeInsets.all(16.0), child: Form( key: formKey, - autovalidate: false, - onWillPop: () { - return Future(() => true); - }, + autovalidateMode: AutovalidateMode.always, + canPop: true, child: ListView( children: [ TextFormField( - initialValue: widget.todo != null ? widget.todo.task : '', + initialValue: widget.todo != null ? widget.todo!.task : '', key: ArchSampleKeys.taskField, autofocus: isEditing ? false : true, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, decoration: InputDecoration( hintText: ArchSampleLocalizations.of(context).newTodoHint, ), - validator: (val) => val.trim().isEmpty + validator: (val) => val != null && val.trim().isEmpty ? ArchSampleLocalizations.of(context).emptyTodoError : null, - onSaved: (value) => _task = value, + onSaved: (value) => _task = value ?? '', ), TextFormField( - initialValue: widget.todo != null ? widget.todo.note : '', + initialValue: widget.todo != null ? widget.todo!.note : '', key: ArchSampleKeys.noteField, maxLines: 10, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, decoration: InputDecoration( hintText: ArchSampleLocalizations.of(context).notesHint, ), - onSaved: (value) => _note = value, - ) + onSaved: (value) => _note = value ?? '', + ), ], ), ), ), floatingActionButton: FloatingActionButton( - key: - isEditing ? ArchSampleKeys.saveTodoFab : ArchSampleKeys.saveNewTodo, + key: isEditing + ? ArchSampleKeys.saveTodoFab + : ArchSampleKeys.saveNewTodo, tooltip: isEditing ? ArchSampleLocalizations.of(context).saveChanges : ArchSampleLocalizations.of(context).addTodo, child: Icon(isEditing ? Icons.check : Icons.add), onPressed: () { - final form = formKey.currentState; - if (form.validate()) { - form.save(); + if (formKey.currentState!.validate()) { + formKey.currentState!.save(); if (isEditing) { - widget.updateTodo(widget.todo.copyWith(task: _task, note: _note)); + widget.updateTodo!( + widget.todo!.copyWith(task: _task, note: _note), + ); } else { - widget.addTodo(Todo( - _task, - note: _note, - )); + widget.addTodo!(Todo(_task, note: _note)); } Navigator.pop(context); diff --git a/simple_bloc_flutter/lib/screens/detail_screen.dart b/simple_bloc_flutter/lib/screens/detail_screen.dart index 75b23238..13a62ee9 100644 --- a/simple_bloc_flutter/lib/screens/detail_screen.dart +++ b/simple_bloc_flutter/lib/screens/detail_screen.dart @@ -1,22 +1,15 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; +import 'package:simple_bloc_flutter_sample/dependency_injection.dart'; import 'package:simple_bloc_flutter_sample/screens/add_edit_screen.dart'; import 'package:simple_bloc_flutter_sample/widgets/loading.dart'; import 'package:simple_blocs/simple_blocs.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class DetailScreen extends StatefulWidget { final String todoId; - final TodoBloc Function() initBloc; - DetailScreen({ - @required this.todoId, - @required this.initBloc, - }) : super(key: ArchSampleKeys.todoDetailsScreen); + const DetailScreen({required this.todoId}) + : super(key: ArchSampleKeys.todoDetailsScreen); @override DetailScreenState createState() { @@ -25,12 +18,12 @@ class DetailScreen extends StatefulWidget { } class DetailScreenState extends State { - TodoBloc todoBloc; + late TodoBloc todoBloc; @override - void initState() { - super.initState(); - todoBloc = widget.initBloc(); + void didChangeDependencies() { + super.didChangeDependencies(); + todoBloc = TodoBloc(Injector.of(context).todosInteractor); } @override @@ -41,11 +34,11 @@ class DetailScreenState extends State { @override Widget build(BuildContext context) { return StreamBuilder( - stream: todoBloc.todo(widget.todoId).where((todo) => todo != null), + stream: todoBloc.todo(widget.todoId), builder: (context, snapshot) { if (!snapshot.hasData) return LoadingSpinner(); - final todo = snapshot.data; + final todo = snapshot.data!; return Scaffold( appBar: AppBar( @@ -59,7 +52,7 @@ class DetailScreenState extends State { todoBloc.deleteTodo(todo.id); Navigator.pop(context, todo); }, - ) + ), ], ), body: Padding( @@ -76,7 +69,8 @@ class DetailScreenState extends State { key: ArchSampleKeys.detailsTodoItemCheckbox, onChanged: (complete) { todoBloc.updateTodo( - todo.copyWith(complete: !todo.complete)); + todo.copyWith(complete: !todo.complete), + ); }, ), ), @@ -85,21 +79,18 @@ class DetailScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), + padding: EdgeInsets.only(top: 8.0, bottom: 16.0), child: Text( todo.task, key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, ), ), Text( todo.note, key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) + style: Theme.of(context).textTheme.titleMedium, + ), ], ), ), @@ -110,11 +101,10 @@ class DetailScreenState extends State { ), floatingActionButton: FloatingActionButton( tooltip: ArchSampleLocalizations.of(context).editTodo, - child: Icon(Icons.edit), key: ArchSampleKeys.editTodoFab, onPressed: () { Navigator.of(context).push( - MaterialPageRoute( + MaterialPageRoute( builder: (context) { return AddEditScreen( todo: todo, @@ -125,6 +115,7 @@ class DetailScreenState extends State { ), ); }, + child: const Icon(Icons.edit), ), ); }, diff --git a/simple_bloc_flutter/lib/screens/home_screen.dart b/simple_bloc_flutter/lib/screens/home_screen.dart index 76329d09..d485d313 100644 --- a/simple_bloc_flutter/lib/screens/home_screen.dart +++ b/simple_bloc_flutter/lib/screens/home_screen.dart @@ -1,12 +1,6 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:meta/meta.dart'; import 'package:rxdart/rxdart.dart'; import 'package:simple_bloc_flutter_sample/dependency_injection.dart'; import 'package:simple_bloc_flutter_sample/localization.dart'; @@ -17,15 +11,13 @@ import 'package:simple_bloc_flutter_sample/widgets/stats_counter.dart'; import 'package:simple_bloc_flutter_sample/widgets/todo_list.dart'; import 'package:simple_bloc_flutter_sample/widgets/todos_bloc_provider.dart'; import 'package:simple_blocs/simple_blocs.dart'; +import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; enum AppTab { todos, stats } class HomeScreen extends StatefulWidget { - final UserRepository repository; - - HomeScreen({@required this.repository}) - : super(key: ArchSampleKeys.homeScreen); + const HomeScreen({super.key}); @override State createState() { @@ -34,14 +26,14 @@ class HomeScreen extends StatefulWidget { } class HomeScreenState extends State { - UserBloc usersBloc; - StreamController tabController; + late UserBloc usersBloc; + late StreamController tabController; @override - void initState() { - super.initState(); + void didChangeDependencies() { + super.didChangeDependencies(); - usersBloc = UserBloc(widget.repository); + usersBloc = UserBloc(Injector.of(context).userRepository); tabController = StreamController(); } @@ -64,7 +56,7 @@ class HomeScreenState extends State { builder: (context, activeTabSnapshot) { return Scaffold( appBar: AppBar( - title: Text(BlocLocalizations.of(context).appTitle), + title: Text(SimpleBlocLocalizations.of(context).appTitle), actions: _buildActions( todosBloc, activeTabSnapshot, @@ -73,25 +65,23 @@ class HomeScreenState extends State { ), body: userSnapshot.hasData ? activeTabSnapshot.data == AppTab.todos - ? TodoList() - : StatsCounter( - buildBloc: () => - StatsBloc(Injector.of(context).todosInteractor), - ) - : LoadingSpinner( - key: ArchSampleKeys.todosLoading, - ), + ? TodoList() + : StatsCounter( + buildBloc: () => + StatsBloc(Injector.of(context).todosInteractor), + ) + : LoadingSpinner(key: ArchSampleKeys.todosLoading), floatingActionButton: FloatingActionButton( key: ArchSampleKeys.addTodoFab, onPressed: () { Navigator.pushNamed(context, ArchSampleRoutes.addTodo); }, - child: Icon(Icons.add), tooltip: ArchSampleLocalizations.of(context).addTodo, + child: const Icon(Icons.add), ), bottomNavigationBar: BottomNavigationBar( key: ArchSampleKeys.tabs, - currentIndex: AppTab.values.indexOf(activeTabSnapshot.data), + currentIndex: AppTab.values.indexOf(activeTabSnapshot.data!), onTap: (index) { tabController.add(AppTab.values[index]); }, @@ -103,11 +93,9 @@ class HomeScreenState extends State { ? ArchSampleKeys.statsTab : ArchSampleKeys.todoTab, ), - title: Text( - tab == AppTab.stats - ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos, - ), + label: tab == AppTab.stats + ? ArchSampleLocalizations.of(context).stats + : ArchSampleLocalizations.of(context).todos, ); }).toList(), ), @@ -141,10 +129,7 @@ class HomeScreenState extends State { todosBloc.allComplete, todosBloc.hasCompletedTodos, (allComplete, hasCompletedTodos) { - return ExtraActionsButtonViewModel( - allComplete, - hasCompletedTodos, - ); + return ExtraActionsButtonViewModel(allComplete, hasCompletedTodos); }, ), builder: (context, snapshot) { @@ -160,7 +145,7 @@ class HomeScreenState extends State { }, ); }, - ) + ), ]; } } diff --git a/simple_bloc_flutter/lib/widgets/extra_actions_button.dart b/simple_bloc_flutter/lib/widgets/extra_actions_button.dart index 1f6955b7..4cabe430 100644 --- a/simple_bloc_flutter/lib/widgets/extra_actions_button.dart +++ b/simple_bloc_flutter/lib/widgets/extra_actions_button.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; @@ -10,12 +6,12 @@ class ExtraActionsButton extends StatelessWidget { final bool allComplete; final bool hasCompletedTodos; - ExtraActionsButton({ - this.onSelected, + const ExtraActionsButton({ + required this.onSelected, this.allComplete = false, this.hasCompletedTodos = true, - Key key, - }) : super(key: key); + super.key, + }); @override Widget build(BuildContext context) { @@ -36,9 +32,7 @@ class ExtraActionsButton extends StatelessWidget { PopupMenuItem( key: ArchSampleKeys.clearCompleted, value: ExtraAction.clearCompleted, - child: Text( - ArchSampleLocalizations.of(context).clearCompleted, - ), + child: Text(ArchSampleLocalizations.of(context).clearCompleted), ), ]; }, diff --git a/simple_bloc_flutter/lib/widgets/filter_button.dart b/simple_bloc_flutter/lib/widgets/filter_button.dart index a0bf6120..bfbef0d5 100644 --- a/simple_bloc_flutter/lib/widgets/filter_button.dart +++ b/simple_bloc_flutter/lib/widgets/filter_button.dart @@ -1,31 +1,30 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:simple_blocs/simple_blocs.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class FilterButton extends StatelessWidget { final PopupMenuItemSelected onSelected; final VisibilityFilter activeFilter; final bool isActive; - FilterButton({this.onSelected, this.activeFilter, this.isActive, Key key}) - : super(key: key); + const FilterButton({ + required this.onSelected, + required this.activeFilter, + required this.isActive, + super.key, + }); @override Widget build(BuildContext context) { - final theme = Theme.of(context); - final defaultStyle = theme.textTheme.body1; - final activeStyle = theme.textTheme.body1.copyWith( - color: theme.accentColor, + final defaultStyle = Theme.of(context).textTheme.bodyMedium; + final activeStyle = defaultStyle?.copyWith( + color: Theme.of(context).colorScheme.secondary, ); final button = _Button( onSelected: onSelected, activeFilter: activeFilter, - activeStyle: activeStyle, - defaultStyle: defaultStyle, + activeStyle: activeStyle!, + defaultStyle: defaultStyle!, ); return AnimatedOpacity( @@ -38,12 +37,11 @@ class FilterButton extends StatelessWidget { class _Button extends StatelessWidget { const _Button({ - Key key, - @required this.onSelected, - @required this.activeFilter, - @required this.activeStyle, - @required this.defaultStyle, - }) : super(key: key); + required this.onSelected, + required this.activeFilter, + required this.activeStyle, + required this.defaultStyle, + }); final PopupMenuItemSelected onSelected; final VisibilityFilter activeFilter; diff --git a/simple_bloc_flutter/lib/widgets/loading.dart b/simple_bloc_flutter/lib/widgets/loading.dart index 0fa4416a..68c0ec55 100644 --- a/simple_bloc_flutter/lib/widgets/loading.dart +++ b/simple_bloc_flutter/lib/widgets/loading.dart @@ -1,16 +1,10 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; class LoadingSpinner extends StatelessWidget { - LoadingSpinner({Key key}) : super(key: key); + const LoadingSpinner({super.key}); @override Widget build(BuildContext context) { - return Center( - child: CircularProgressIndicator(), - ); + return Center(child: CircularProgressIndicator()); } } diff --git a/simple_bloc_flutter/lib/widgets/stats_counter.dart b/simple_bloc_flutter/lib/widgets/stats_counter.dart index 17d2d98d..2f374f6a 100644 --- a/simple_bloc_flutter/lib/widgets/stats_counter.dart +++ b/simple_bloc_flutter/lib/widgets/stats_counter.dart @@ -1,18 +1,14 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:simple_blocs/simple_blocs.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class StatsCounter extends StatefulWidget { final StatsBloc Function() buildBloc; - StatsCounter({Key key, @required this.buildBloc}) - : super(key: key ?? ArchSampleKeys.statsCounter); + const StatsCounter({ + super.key = ArchSampleKeys.statsCounter, + required this.buildBloc, + }); @override StatsCounterState createState() { @@ -21,7 +17,7 @@ class StatsCounter extends StatefulWidget { } class StatsCounterState extends State { - StatsBloc bloc; + late StatsBloc bloc; @override void initState() { @@ -39,7 +35,7 @@ class StatsCounterState extends State { padding: EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -49,7 +45,7 @@ class StatsCounterState extends State { builder: (context, snapshot) => Text( '${snapshot.data ?? 0}', key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ), @@ -57,7 +53,7 @@ class StatsCounterState extends State { padding: EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -68,11 +64,11 @@ class StatsCounterState extends State { return Text( '${snapshot.data ?? 0}', key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ); }, ), - ) + ), ], ), ); diff --git a/simple_bloc_flutter/lib/widgets/todo_item.dart b/simple_bloc_flutter/lib/widgets/todo_item.dart index da9b7069..f4ee3975 100644 --- a/simple_bloc_flutter/lib/widgets/todo_item.dart +++ b/simple_bloc_flutter/lib/widgets/todo_item.dart @@ -1,23 +1,19 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; import 'package:simple_blocs/simple_blocs.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class TodoItem extends StatelessWidget { final DismissDirectionCallback onDismissed; final GestureTapCallback onTap; - final ValueChanged onCheckboxChanged; + final ValueChanged onCheckboxChanged; final Todo todo; - TodoItem({ - @required this.onDismissed, - @required this.onTap, - @required this.onCheckboxChanged, - @required this.todo, + const TodoItem({ + super.key, + required this.onDismissed, + required this.onTap, + required this.onCheckboxChanged, + required this.todo, }); @override @@ -35,14 +31,14 @@ class TodoItem extends StatelessWidget { title: Text( todo.task, key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), subtitle: Text( todo.note, key: ArchSampleKeys.todoItemNote(todo.id), maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ); diff --git a/simple_bloc_flutter/lib/widgets/todo_list.dart b/simple_bloc_flutter/lib/widgets/todo_list.dart index c6665825..f516fdd1 100644 --- a/simple_bloc_flutter/lib/widgets/todo_list.dart +++ b/simple_bloc_flutter/lib/widgets/todo_list.dart @@ -1,25 +1,20 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'package:simple_bloc_flutter_sample/dependency_injection.dart'; import 'package:simple_bloc_flutter_sample/screens/detail_screen.dart'; import 'package:simple_bloc_flutter_sample/widgets/loading.dart'; import 'package:simple_bloc_flutter_sample/widgets/todo_item.dart'; import 'package:simple_bloc_flutter_sample/widgets/todos_bloc_provider.dart'; import 'package:simple_blocs/simple_blocs.dart'; +import 'package:todos_app_core/todos_app_core.dart'; class TodoList extends StatelessWidget { - TodoList({Key key}) : super(key: key); + const TodoList({super.key}); @override Widget build(BuildContext context) { return StreamBuilder>( stream: TodosBlocProvider.of(context).visibleTodos, builder: (context, snapshot) => snapshot.hasData - ? _buildList(snapshot.data) + ? _buildList(snapshot.data!) : LoadingSpinner(key: ArchSampleKeys.todosLoading), ); } @@ -37,25 +32,24 @@ class TodoList extends StatelessWidget { _removeTodo(context, todo); }, onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) { - return DetailScreen( - todoId: todo.id, - initBloc: () => - TodoBloc(Injector.of(context).todosInteractor), - ); - }, - ), - ).then((todo) { - if (todo is Todo) { - _showUndoSnackbar(context, todo); - } - }); + Navigator.of(context) + .push( + MaterialPageRoute( + builder: (context) => DetailScreen(todoId: todo.id), + ), + ) + .then((todo) { + if (todo is Todo) { + if (context.mounted) { + _showUndoSnackbar(context, todo); + } + } + }); }, onCheckboxChanged: (complete) { - TodosBlocProvider.of(context) - .updateTodo(todo.copyWith(complete: !todo.complete)); + TodosBlocProvider.of( + context, + ).updateTodo(todo.copyWith(complete: !todo.complete)); }, ); }, @@ -86,6 +80,6 @@ class TodoList extends StatelessWidget { ), ); - Scaffold.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(context).showSnackBar(snackBar); } } diff --git a/simple_bloc_flutter/lib/widgets/todos_bloc_provider.dart b/simple_bloc_flutter/lib/widgets/todos_bloc_provider.dart index c0319bfa..0b62b639 100644 --- a/simple_bloc_flutter/lib/widgets/todos_bloc_provider.dart +++ b/simple_bloc_flutter/lib/widgets/todos_bloc_provider.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:simple_blocs/simple_blocs.dart'; @@ -10,20 +5,19 @@ class TodosBlocProvider extends StatefulWidget { final Widget child; final TodosListBloc bloc; - TodosBlocProvider({Key key, @required this.child, @required this.bloc}) - : super(key: key); + const TodosBlocProvider({required this.child, required this.bloc, super.key}); @override - _TodosBlocProviderState createState() => _TodosBlocProviderState(); + TodosBlocProviderState createState() => TodosBlocProviderState(); static TodosListBloc of(BuildContext context) { return context - .dependOnInheritedWidgetOfExactType<_TodosBlocProvider>() + .dependOnInheritedWidgetOfExactType<_TodosBlocProvider>()! .bloc; } } -class _TodosBlocProviderState extends State { +class TodosBlocProviderState extends State { @override Widget build(BuildContext context) { return _TodosBlocProvider(bloc: widget.bloc, child: widget.child); @@ -39,11 +33,7 @@ class _TodosBlocProviderState extends State { class _TodosBlocProvider extends InheritedWidget { final TodosListBloc bloc; - _TodosBlocProvider({ - Key key, - @required this.bloc, - @required Widget child, - }) : super(key: key, child: child); + const _TodosBlocProvider({required super.child, required this.bloc}); @override bool updateShouldNotify(_TodosBlocProvider old) => bloc != old.bloc; diff --git a/simple_bloc_flutter/linux/.gitignore b/simple_bloc_flutter/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/simple_bloc_flutter/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/simple_bloc_flutter/linux/CMakeLists.txt b/simple_bloc_flutter/linux/CMakeLists.txt new file mode 100644 index 00000000..73c66cc4 --- /dev/null +++ b/simple_bloc_flutter/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +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 "simple_bloc_flutter_sample") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.simple_bloc_flutter_sample") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +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() + +# 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() + +# 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_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# 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 +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# 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() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +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) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/simple_bloc_flutter/linux/flutter/CMakeLists.txt b/simple_bloc_flutter/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/simple_bloc_flutter/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +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. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# 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/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter 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. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/simple_bloc_flutter/linux/flutter/generated_plugin_registrant.cc b/simple_bloc_flutter/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e71a16d2 --- /dev/null +++ b/simple_bloc_flutter/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/simple_bloc_flutter/linux/flutter/generated_plugin_registrant.h b/simple_bloc_flutter/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/simple_bloc_flutter/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/simple_bloc_flutter/linux/flutter/generated_plugins.cmake b/simple_bloc_flutter/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/simple_bloc_flutter/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + 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}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/simple_bloc_flutter/linux/runner/CMakeLists.txt b/simple_bloc_flutter/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/simple_bloc_flutter/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "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 +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/simple_bloc_flutter/linux/runner/main.cc b/simple_bloc_flutter/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/simple_bloc_flutter/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/simple_bloc_flutter/linux/runner/my_application.cc b/simple_bloc_flutter/linux/runner/my_application.cc new file mode 100644 index 00000000..5db96884 --- /dev/null +++ b/simple_bloc_flutter/linux/runner/my_application.cc @@ -0,0 +1,144 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView *view) +{ + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // 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 + // desktop). + // 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. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "simple_bloc_flutter_sample"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "simple_bloc_flutter_sample"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/simple_bloc_flutter/linux/runner/my_application.h b/simple_bloc_flutter/linux/runner/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/simple_bloc_flutter/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/simple_bloc_flutter/macos/.gitignore b/simple_bloc_flutter/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/simple_bloc_flutter/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/simple_bloc_flutter/macos/Flutter/Flutter-Debug.xcconfig b/simple_bloc_flutter/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/simple_bloc_flutter/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/simple_bloc_flutter/macos/Flutter/Flutter-Release.xcconfig b/simple_bloc_flutter/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/simple_bloc_flutter/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/simple_bloc_flutter/macos/Flutter/GeneratedPluginRegistrant.swift b/simple_bloc_flutter/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b8e2b22f --- /dev/null +++ b/simple_bloc_flutter/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/simple_bloc_flutter/macos/Podfile b/simple_bloc_flutter/macos/Podfile new file mode 100644 index 00000000..ff5ddb3b --- /dev/null +++ b/simple_bloc_flutter/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/simple_bloc_flutter/macos/Podfile.lock b/simple_bloc_flutter/macos/Podfile.lock new file mode 100644 index 00000000..d2f9a639 --- /dev/null +++ b/simple_bloc_flutter/macos/Podfile.lock @@ -0,0 +1,30 @@ +PODS: + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + +SPEC CHECKSUMS: + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.16.2 diff --git a/simple_bloc_flutter/macos/Runner.xcodeproj/project.pbxproj b/simple_bloc_flutter/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..54eb3cdd --- /dev/null +++ b/simple_bloc_flutter/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 85DA56021CE45A760AA3A54E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 302B63344A18E0A9F0A76FFC /* Pods_Runner.framework */; }; + EB98561EE9A6EEBB9827F08C /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBA83EC4DF44D59B0B4B1155 /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 029192B5D938D2D1F537DF38 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 2024E86BF091F3C84436D6C3 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 302B63344A18E0A9F0A76FFC /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* simple_bloc_flutter_sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = simple_bloc_flutter_sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 71B571842B1C7DE4FE81DCD8 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 887D1F40AE6DBE8F286247FE /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + EE9DC3DED0D3A86568B4D843 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + F1FD579DEBCFDBCD6534F16B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + FBA83EC4DF44D59B0B4B1155 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EB98561EE9A6EEBB9827F08C /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 85DA56021CE45A760AA3A54E /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + B787C8DD073B6601A153460F /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* simple_bloc_flutter_sample.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + B787C8DD073B6601A153460F /* Pods */ = { + isa = PBXGroup; + children = ( + F1FD579DEBCFDBCD6534F16B /* Pods-Runner.debug.xcconfig */, + 2024E86BF091F3C84436D6C3 /* Pods-Runner.release.xcconfig */, + 71B571842B1C7DE4FE81DCD8 /* Pods-Runner.profile.xcconfig */, + 029192B5D938D2D1F537DF38 /* Pods-RunnerTests.debug.xcconfig */, + EE9DC3DED0D3A86568B4D843 /* Pods-RunnerTests.release.xcconfig */, + 887D1F40AE6DBE8F286247FE /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 302B63344A18E0A9F0A76FFC /* Pods_Runner.framework */, + FBA83EC4DF44D59B0B4B1155 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 3F6837CE77C83266F7AAC2C4 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + E1F41E112214C56C2724B732 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 0CA2C25714A4EB720EAF8762 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* simple_bloc_flutter_sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 0CA2C25714A4EB720EAF8762 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 3F6837CE77C83266F7AAC2C4 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + E1F41E112214C56C2724B732 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 029192B5D938D2D1F537DF38 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/simple_bloc_flutter_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/simple_bloc_flutter_sample"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EE9DC3DED0D3A86568B4D843 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/simple_bloc_flutter_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/simple_bloc_flutter_sample"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 887D1F40AE6DBE8F286247FE /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutterSample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/simple_bloc_flutter_sample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/simple_bloc_flutter_sample"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/simple_bloc_flutter/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/simple_bloc_flutter/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/simple_bloc_flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/simple_bloc_flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..cbba2d7a --- /dev/null +++ b/simple_bloc_flutter/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/simple_bloc_flutter/macos/Runner.xcworkspace/contents.xcworkspacedata b/simple_bloc_flutter/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/simple_bloc_flutter/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/simple_bloc_flutter/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/simple_bloc_flutter/macos/Runner/AppDelegate.swift b/simple_bloc_flutter/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/simple_bloc_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/simple_bloc_flutter/macos/Runner/Base.lproj/MainMenu.xib b/simple_bloc_flutter/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/simple_bloc_flutter/macos/Runner/Configs/AppInfo.xcconfig b/simple_bloc_flutter/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..ccfc52c8 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// 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 +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = simple_bloc_flutter_sample + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.simpleBlocFlutterSample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/simple_bloc_flutter/macos/Runner/Configs/Debug.xcconfig b/simple_bloc_flutter/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/simple_bloc_flutter/macos/Runner/Configs/Release.xcconfig b/simple_bloc_flutter/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/simple_bloc_flutter/macos/Runner/Configs/Warnings.xcconfig b/simple_bloc_flutter/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/simple_bloc_flutter/macos/Runner/DebugProfile.entitlements b/simple_bloc_flutter/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/simple_bloc_flutter/macos/Runner/Info.plist b/simple_bloc_flutter/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/simple_bloc_flutter/macos/Runner/MainFlutterWindow.swift b/simple_bloc_flutter/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/simple_bloc_flutter/macos/Runner/Release.entitlements b/simple_bloc_flutter/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/simple_bloc_flutter/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/simple_bloc_flutter/macos/RunnerTests/RunnerTests.swift b/simple_bloc_flutter/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/simple_bloc_flutter/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/simple_bloc_flutter/pubspec.yaml b/simple_bloc_flutter/pubspec.yaml index 0a5366c7..6333104e 100644 --- a/simple_bloc_flutter/pubspec.yaml +++ b/simple_bloc_flutter/pubspec.yaml @@ -12,33 +12,34 @@ description: A new Flutter project. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html version: 1.0.0+1 +publish_to: "none" environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ^3.9.0 dependencies: flutter: sdk: flutter - todos_repository_local_storage: - path: ../todos_repository_local_storage - firebase_flutter_repository: - path: ../firebase_flutter_repository todos_app_core: path: ../todos_app_core + todos_repository_core: + path: ../todos_repository_core + todos_repository_local_storage: + path: ../todos_repository_local_storage simple_blocs: path: ../simple_blocs - rxdart: ^0.23.1 - key_value_store_flutter: - key_value_store_web: + rxdart: ^0.28.0 shared_preferences: dev_dependencies: + flutter_lints: flutter_test: sdk: flutter - flutter_driver: + integration_test: sdk: flutter test: mockito: + build_runner: integration_tests: path: ../integration_tests @@ -47,7 +48,6 @@ dev_dependencies: # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. diff --git a/simple_bloc_flutter/test/home_screen_test.dart b/simple_bloc_flutter/test/home_screen_test.dart new file mode 100644 index 00000000..8114d872 --- /dev/null +++ b/simple_bloc_flutter/test/home_screen_test.dart @@ -0,0 +1,171 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:simple_bloc_flutter_sample/anonymous_user_repository.dart'; +import 'package:simple_bloc_flutter_sample/dependency_injection.dart'; +import 'package:simple_bloc_flutter_sample/localization.dart'; +import 'package:simple_bloc_flutter_sample/screens/home_screen.dart'; +import 'package:simple_bloc_flutter_sample/widgets/todos_bloc_provider.dart'; +import 'package:simple_blocs/simple_blocs.dart'; +import 'package:todos_app_core/todos_app_core.dart'; +import 'package:todos_repository_core/todos_repository_core.dart'; + +import 'home_screen_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec(), MockSpec()]) +void main() { + group('HomeScreen', () { + final todoListFinder = find.byKey(ArchSampleKeys.todoList); + final todoItem1Finder = find.byKey(ArchSampleKeys.todoItem('1')); + final todoItem2Finder = find.byKey(ArchSampleKeys.todoItem('2')); + final todoItem3Finder = find.byKey(ArchSampleKeys.todoItem('3')); + + testWidgets('should render loading indicator at first', (tester) async { + await tester.pumpWidget( + _TestWidget( + todosInteractor: MockTodosInteractor(), + userRepository: AnonymousUserRepository(), + ), + ); + await tester.pump(Duration.zero); + + expect(find.byKey(ArchSampleKeys.todosLoading), findsOneWidget); + }); + + testWidgets('should display a list after loading todos', (tester) async { + final handle = tester.ensureSemantics(); + final interactor = MockTodosInteractor(); + + when( + interactor.todos, + ).thenAnswer((_) => Stream.fromIterable([_TestWidget._defaultTodos])); + + await tester.pumpWidget( + _TestWidget( + todosInteractor: interactor, + userRepository: AnonymousUserRepository(), + ), + ); + await tester.pumpAndSettle(); + + final checkbox1 = find.descendant( + of: find.byKey(ArchSampleKeys.todoItemCheckbox('1')), + matching: find.byType(Focus), + ); + final checkbox2 = find.descendant( + of: find.byKey(ArchSampleKeys.todoItemCheckbox('2')), + matching: find.byType(Focus), + ); + final checkbox3 = find.descendant( + of: find.byKey(ArchSampleKeys.todoItemCheckbox('3')), + matching: find.byType(Focus), + ); + + expect(todoListFinder, findsOneWidget); + expect(todoItem1Finder, findsOneWidget); + expect(find.text('T1'), findsOneWidget); + expect(find.text('N1'), findsOneWidget); + expect(tester.getSemantics(checkbox1), isChecked(false)); + expect(todoItem2Finder, findsOneWidget); + expect(find.text('T2'), findsOneWidget); + expect(tester.getSemantics(checkbox2), isChecked(false)); + expect(todoItem3Finder, findsOneWidget); + expect(find.text('T3'), findsOneWidget); + expect(tester.getSemantics(checkbox3), isChecked(true)); + + handle.dispose(); + }); + + testWidgets('should remove todos using a dismissible', (tester) async { + final interactor = MockTodosInteractor(); + + when( + interactor.todos, + ).thenAnswer((_) => Stream.fromIterable([_TestWidget._defaultTodos])); + + await tester.pumpWidget( + _TestWidget( + todosInteractor: interactor, + userRepository: AnonymousUserRepository(), + ), + ); + await tester.pumpAndSettle(); + await tester.drag(todoItem1Finder, Offset(-1000, 0)); + await tester.pumpAndSettle(Duration(seconds: 5)); + + expect(todoItem1Finder, findsNothing); + expect(todoItem2Finder, findsOneWidget); + expect(todoItem3Finder, findsOneWidget); + }); + + testWidgets('should display stats when switching tabs', (tester) async { + final interactor = MockTodosInteractor(); + + when( + interactor.todos, + ).thenAnswer((_) => Stream.fromIterable([_TestWidget._defaultTodos])); + + await tester.pumpWidget( + _TestWidget( + todosInteractor: interactor, + userRepository: AnonymousUserRepository(), + ), + ); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(ArchSampleKeys.statsTab)); + await tester.pump(); + + expect(find.byKey(ArchSampleKeys.statsNumActive), findsOneWidget); + expect(find.byKey(ArchSampleKeys.statsNumActive), findsOneWidget); + }); + }); +} + +class _TestWidget extends StatelessWidget { + const _TestWidget({ + required this.todosInteractor, + required this.userRepository, + }); + + final TodosInteractor todosInteractor; + final UserRepository userRepository; + + @override + Widget build(BuildContext context) { + return Injector( + todosInteractor: todosInteractor, + userRepository: userRepository, + child: TodosBlocProvider( + bloc: TodosListBloc(todosInteractor), + child: MaterialApp( + localizationsDelegates: [ + SimpleBlocLocalizationsDelegate(), + ArchSampleLocalizationsDelegate(), + ], + home: const HomeScreen(), + ), + ), + ); + } + + static List get _defaultTodos { + return [ + Todo('T1', id: '1', note: 'N1'), + Todo('T2', id: '2'), + Todo('T3', id: '3', complete: true), + ]; + } +} + +Matcher isChecked(bool isChecked) { + return matchesSemantics( + isChecked: isChecked, + hasTapAction: true, + hasFocusAction: true, + hasCheckedState: true, + isFocusable: true, + hasEnabledState: true, + isEnabled: true, + ); +} diff --git a/simple_bloc_flutter/test/home_screen_test.mocks.dart b/simple_bloc_flutter/test/home_screen_test.mocks.dart new file mode 100644 index 00000000..a3a33aa8 --- /dev/null +++ b/simple_bloc_flutter/test/home_screen_test.mocks.dart @@ -0,0 +1,156 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in simple_bloc_flutter_sample/test/home_screen_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:simple_blocs/simple_blocs.dart' as _i3; +import 'package:todos_repository_core/todos_repository_core.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeReactiveTodosRepository_0 extends _i1.SmartFake + implements _i2.ReactiveTodosRepository { + _FakeReactiveTodosRepository_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakeUserEntity_1 extends _i1.SmartFake implements _i2.UserEntity { + _FakeUserEntity_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [TodosInteractor]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodosInteractor extends _i1.Mock implements _i3.TodosInteractor { + @override + _i2.ReactiveTodosRepository get repository => + (super.noSuchMethod( + Invocation.getter(#repository), + returnValue: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + returnValueForMissingStub: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + ) + as _i2.ReactiveTodosRepository); + + @override + _i4.Stream> get todos => + (super.noSuchMethod( + Invocation.getter(#todos), + returnValue: _i4.Stream>.empty(), + returnValueForMissingStub: _i4.Stream>.empty(), + ) + as _i4.Stream>); + + @override + _i4.Stream get allComplete => + (super.noSuchMethod( + Invocation.getter(#allComplete), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream get hasCompletedTodos => + (super.noSuchMethod( + Invocation.getter(#hasCompletedTodos), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream<_i3.Todo> todo(String? id) => + (super.noSuchMethod( + Invocation.method(#todo, [id]), + returnValue: _i4.Stream<_i3.Todo>.empty(), + returnValueForMissingStub: _i4.Stream<_i3.Todo>.empty(), + ) + as _i4.Stream<_i3.Todo>); + + @override + _i4.Future updateTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future addNewTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future deleteTodo(String? id) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [id]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future clearCompleted([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#clearCompleted, [_0]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future> toggleAll([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#toggleAll, [_0]), + returnValue: _i4.Future>.value([]), + returnValueForMissingStub: _i4.Future>.value( + [], + ), + ) + as _i4.Future>); +} + +/// A class which mocks [UserRepository]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockUserRepository extends _i1.Mock implements _i2.UserRepository { + @override + _i4.Future<_i2.UserEntity> login() => + (super.noSuchMethod( + Invocation.method(#login, []), + returnValue: _i4.Future<_i2.UserEntity>.value( + _FakeUserEntity_1(this, Invocation.method(#login, [])), + ), + returnValueForMissingStub: _i4.Future<_i2.UserEntity>.value( + _FakeUserEntity_1(this, Invocation.method(#login, [])), + ), + ) + as _i4.Future<_i2.UserEntity>); +} diff --git a/simple_bloc_flutter/test_driver/integration_test.dart b/simple_bloc_flutter/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/simple_bloc_flutter/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/simple_bloc_flutter/test_driver/todo_app.dart b/simple_bloc_flutter/test_driver/todo_app.dart deleted file mode 100644 index fd474953..00000000 --- a/simple_bloc_flutter/test_driver/todo_app.dart +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter_driver/driver_extension.dart'; -import 'package:simple_bloc_flutter_sample/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/simple_bloc_flutter/test_driver/todo_app_test.dart b/simple_bloc_flutter/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/simple_bloc_flutter/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/simple_bloc_flutter/web/favicon.png b/simple_bloc_flutter/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/simple_bloc_flutter/web/favicon.png differ diff --git a/simple_bloc_flutter/web/icons/Icon-192.png b/simple_bloc_flutter/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/simple_bloc_flutter/web/icons/Icon-192.png differ diff --git a/simple_bloc_flutter/web/icons/Icon-512.png b/simple_bloc_flutter/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/simple_bloc_flutter/web/icons/Icon-512.png differ diff --git a/simple_bloc_flutter/web/icons/Icon-maskable-192.png b/simple_bloc_flutter/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/simple_bloc_flutter/web/icons/Icon-maskable-192.png differ diff --git a/simple_bloc_flutter/web/icons/Icon-maskable-512.png b/simple_bloc_flutter/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/simple_bloc_flutter/web/icons/Icon-maskable-512.png differ diff --git a/simple_bloc_flutter/web/index.html b/simple_bloc_flutter/web/index.html index 515108bd..dfc1c678 100644 --- a/simple_bloc_flutter/web/index.html +++ b/simple_bloc_flutter/web/index.html @@ -1,10 +1,38 @@ + + + - simple_bloc_flutter + + + + + + + + + + + + + simple_bloc_flutter_sample + - + diff --git a/simple_bloc_flutter/web/manifest.json b/simple_bloc_flutter/web/manifest.json new file mode 100644 index 00000000..acd22c0a --- /dev/null +++ b/simple_bloc_flutter/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "simple_bloc_flutter_sample", + "short_name": "simple_bloc_flutter_sample", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/simple_bloc_flutter/windows/.gitignore b/simple_bloc_flutter/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/simple_bloc_flutter/windows/.gitignore @@ -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/ diff --git a/simple_bloc_flutter/windows/CMakeLists.txt b/simple_bloc_flutter/windows/CMakeLists.txt new file mode 100644 index 00000000..16fc0ce1 --- /dev/null +++ b/simple_bloc_flutter/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(simple_bloc_flutter_sample 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 "simple_bloc_flutter_sample") + +# 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) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_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 "$") +# 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) diff --git a/simple_bloc_flutter/windows/flutter/CMakeLists.txt b/simple_bloc_flutter/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/simple_bloc_flutter/windows/flutter/CMakeLists.txt @@ -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} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/simple_bloc_flutter/windows/flutter/generated_plugin_registrant.cc b/simple_bloc_flutter/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/simple_bloc_flutter/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/simple_bloc_flutter/windows/flutter/generated_plugin_registrant.h b/simple_bloc_flutter/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/simple_bloc_flutter/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/simple_bloc_flutter/windows/flutter/generated_plugins.cmake b/simple_bloc_flutter/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/simple_bloc_flutter/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +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 $) + 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) diff --git a/simple_bloc_flutter/windows/runner/CMakeLists.txt b/simple_bloc_flutter/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/simple_bloc_flutter/windows/runner/CMakeLists.txt @@ -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) diff --git a/simple_bloc_flutter/windows/runner/Runner.rc b/simple_bloc_flutter/windows/runner/Runner.rc new file mode 100644 index 00000000..d6f8dfcd --- /dev/null +++ b/simple_bloc_flutter/windows/runner/Runner.rc @@ -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", "com.example" "\0" + VALUE "FileDescription", "simple_bloc_flutter_sample" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "simple_bloc_flutter_sample" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "simple_bloc_flutter_sample.exe" "\0" + VALUE "ProductName", "simple_bloc_flutter_sample" "\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 diff --git a/simple_bloc_flutter/windows/runner/flutter_window.cpp b/simple_bloc_flutter/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/simple_bloc_flutter/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#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( + 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 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); +} diff --git a/simple_bloc_flutter/windows/runner/flutter_window.h b/simple_bloc_flutter/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/simple_bloc_flutter/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#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_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/simple_bloc_flutter/windows/runner/main.cpp b/simple_bloc_flutter/windows/runner/main.cpp new file mode 100644 index 00000000..f9abb2d6 --- /dev/null +++ b/simple_bloc_flutter/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 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"simple_bloc_flutter_sample", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/simple_bloc_flutter/windows/runner/resource.h b/simple_bloc_flutter/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/simple_bloc_flutter/windows/runner/resource.h @@ -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 diff --git a/simple_bloc_flutter/windows/runner/resources/app_icon.ico b/simple_bloc_flutter/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/simple_bloc_flutter/windows/runner/resources/app_icon.ico differ diff --git a/simple_bloc_flutter/windows/runner/runner.exe.manifest b/simple_bloc_flutter/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/simple_bloc_flutter/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/simple_bloc_flutter/windows/runner/utils.cpp b/simple_bloc_flutter/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/simple_bloc_flutter/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +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 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::vector 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; +} diff --git a/simple_bloc_flutter/windows/runner/utils.h b/simple_bloc_flutter/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/simple_bloc_flutter/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// 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, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/simple_bloc_flutter/windows/runner/win32_window.cpp b/simple_bloc_flutter/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/simple_bloc_flutter/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#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(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( + 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(origin.x), + static_cast(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(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(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(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( + 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)); + } +} diff --git a/simple_bloc_flutter/windows/runner/win32_window.h b/simple_bloc_flutter/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/simple_bloc_flutter/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// 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_ diff --git a/simple_blocs/.gitignore b/simple_blocs/.gitignore index 1410a619..3cceda55 100644 --- a/simple_blocs/.gitignore +++ b/simple_blocs/.gitignore @@ -1,9 +1,7 @@ -# Files and directories created by pub -.packages -.pub/ -build/ -# Remove the following pattern if you wish to check in your lock file -pubspec.lock +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ -# Directory created by dartdoc -doc/api/ +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/simple_blocs/CHANGELOG.md b/simple_blocs/CHANGELOG.md index 791a857f..effe43c8 100644 --- a/simple_blocs/CHANGELOG.md +++ b/simple_blocs/CHANGELOG.md @@ -1,5 +1,3 @@ -# Changelog +## 1.0.0 -## 0.0.1 - -- Initial version, created by Stagehand +- Initial version. diff --git a/simple_blocs/README.md b/simple_blocs/README.md index 90a4993d..8831761b 100644 --- a/simple_blocs/README.md +++ b/simple_blocs/README.md @@ -1,22 +1,39 @@ -# blocs + -## Usage +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. -A simple usage example: +## Getting started - import 'package:simple_blocs/blocs.dart'; +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage - main() { - var awesome = new Awesome(); - } +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. -## Features and bugs +```dart +const like = 'sample'; +``` -Please file feature requests and bugs at the [issue tracker][tracker]. +## Additional information -[tracker]: http://example.com/issues/replaceme +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/simple_blocs/analysis_options.yaml b/simple_blocs/analysis_options.yaml index 97d4b470..f798e77a 100644 --- a/simple_blocs/analysis_options.yaml +++ b/simple_blocs/analysis_options.yaml @@ -1,14 +1,32 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + analyzer: -# exclude: -# - path/to/excluded/files/** - -# Lint rules and documentation, see http://dart-lang.github.io/linter/lints -linter: - rules: - - cancel_subscriptions - - hash_and_equals - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - test_types_in_equals - - unrelated_type_equality_checks - - valid_regexps + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +# linter: +# rules: +# - camel_case_types + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/simple_blocs/lib/simple_blocs.dart b/simple_blocs/lib/simple_blocs.dart index eac5029b..4448606d 100644 --- a/simple_blocs/lib/simple_blocs.dart +++ b/simple_blocs/lib/simple_blocs.dart @@ -1,9 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -library blocs; - export 'src/models/models.dart'; export 'src/stats_bloc.dart'; export 'src/todo_bloc.dart'; diff --git a/simple_blocs/lib/src/models/models.dart b/simple_blocs/lib/src/models/models.dart index 3d53fea1..977d8087 100644 --- a/simple_blocs/lib/src/models/models.dart +++ b/simple_blocs/lib/src/models/models.dart @@ -1,6 +1,2 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - export 'package:simple_blocs/src/models/todo.dart'; export 'package:simple_blocs/src/models/visibility_filter.dart'; diff --git a/simple_blocs/lib/src/models/todo.dart b/simple_blocs/lib/src/models/todo.dart index f99d773a..b45dac02 100644 --- a/simple_blocs/lib/src/models/todo.dart +++ b/simple_blocs/lib/src/models/todo.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:meta/meta.dart'; import 'package:simple_blocs/src/uuid.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -13,11 +9,10 @@ class Todo { final String note; final String task; - Todo(this.task, {this.complete = false, String note = '', String id}) - : this.note = note ?? '', - this.id = id ?? Uuid().generateV4(); + Todo(this.task, {this.complete = false, this.note = '', String? id}) + : id = id ?? Uuid().generateV4(); - Todo copyWith({bool complete, String id, String note, String task}) { + Todo copyWith({bool? complete, String? id, String? note, String? task}) { return Todo( task ?? this.task, complete: complete ?? this.complete, @@ -52,9 +47,9 @@ class Todo { static Todo fromEntity(TodoEntity entity) { return Todo( entity.task, - complete: entity.complete ?? false, + complete: entity.complete, note: entity.note, - id: entity.id ?? Uuid().generateV4(), + id: entity.id, ); } } diff --git a/simple_blocs/lib/src/models/visibility_filter.dart b/simple_blocs/lib/src/models/visibility_filter.dart index 11f11982..a47beca1 100644 --- a/simple_blocs/lib/src/models/visibility_filter.dart +++ b/simple_blocs/lib/src/models/visibility_filter.dart @@ -1,5 +1 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - enum VisibilityFilter { all, active, completed } diff --git a/simple_blocs/lib/src/stats_bloc.dart b/simple_blocs/lib/src/stats_bloc.dart index 07f54923..8b8edf98 100644 --- a/simple_blocs/lib/src/stats_bloc.dart +++ b/simple_blocs/lib/src/stats_bloc.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:simple_blocs/src/models/models.dart'; @@ -13,9 +9,13 @@ class StatsBloc { StatsBloc(TodosInteractor interactor) : _interactor = interactor; // Outputs - Stream get numActive => _interactor.todos.map((List todos) => - todos.fold(0, (sum, todo) => !todo.complete ? ++sum : sum)); + Stream get numActive => _interactor.todos.map( + (List todos) => + todos.fold(0, (sum, todo) => !todo.complete ? ++sum : sum), + ); - Stream get numComplete => _interactor.todos.map((List todos) => - todos.fold(0, (sum, todo) => todo.complete ? ++sum : sum)); + Stream get numComplete => _interactor.todos.map( + (List todos) => + todos.fold(0, (sum, todo) => todo.complete ? ++sum : sum), + ); } diff --git a/simple_blocs/lib/src/todo_bloc.dart b/simple_blocs/lib/src/todo_bloc.dart index e532fcc3..f13eaf21 100644 --- a/simple_blocs/lib/src/todo_bloc.dart +++ b/simple_blocs/lib/src/todo_bloc.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:simple_blocs/src/models/models.dart'; diff --git a/simple_blocs/lib/src/todos_interactor.dart b/simple_blocs/lib/src/todos_interactor.dart index bbe2d1d3..945ee7ea 100644 --- a/simple_blocs/lib/src/todos_interactor.dart +++ b/simple_blocs/lib/src/todos_interactor.dart @@ -1,9 +1,7 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; +import 'package:collection/collection.dart'; +import 'package:rxdart/rxdart.dart'; import 'package:simple_blocs/simple_blocs.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -18,18 +16,15 @@ class TodosInteractor { TodosInteractor(this.repository); Stream> get todos { - return repository - .todos() - .map((entities) => entities.map(Todo.fromEntity).toList()); + return repository.todos().map( + (entities) => entities.map(Todo.fromEntity).toList(), + ); } Stream todo(String id) { - return todos.map((todos) { - return todos.firstWhere( - (todo) => todo.id == id, - orElse: () => null, - ); - }).where((todo) => todo != null); + return todos + .map((todos) => todos.firstWhereOrNull((todo) => todo.id == id)) + .whereNotNull(); } Stream get allComplete => todos.map(_allComplete); @@ -49,7 +44,8 @@ class TodosInteractor { final updates = await todos.map(_todosToUpdate).first; return Future.wait( - updates.map((update) => repository.updateTodo(update.toEntity()))); + updates.map((update) => repository.updateTodo(update.toEntity())), + ); } static bool _hasCompletedTodos(List todos) { diff --git a/simple_blocs/lib/src/todos_list_bloc.dart b/simple_blocs/lib/src/todos_list_bloc.dart index 4eeefbc0..cb1cf6d7 100644 --- a/simple_blocs/lib/src/todos_list_bloc.dart +++ b/simple_blocs/lib/src/todos_list_bloc.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:rxdart/rxdart.dart'; @@ -54,7 +50,6 @@ class TodosListBloc { case VisibilityFilter.completed: return todo.complete; case VisibilityFilter.all: - default: return true; } }).toList(); diff --git a/simple_blocs/lib/src/user_bloc.dart b/simple_blocs/lib/src/user_bloc.dart index c121d731..2dc34359 100644 --- a/simple_blocs/lib/src/user_bloc.dart +++ b/simple_blocs/lib/src/user_bloc.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -13,5 +9,5 @@ class UserBloc { Stream login() => _repository.login().asStream().asBroadcastStream(); - UserBloc(UserRepository repository) : this._repository = repository; + UserBloc(UserRepository repository) : _repository = repository; } diff --git a/simple_blocs/lib/src/uuid.dart b/simple_blocs/lib/src/uuid.dart index 1b6b26da..73d193cb 100644 --- a/simple_blocs/lib/src/uuid.dart +++ b/simple_blocs/lib/src/uuid.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:math'; /// A UUID generator, useful for generating unique IDs for your Todos. diff --git a/simple_blocs/pubspec.yaml b/simple_blocs/pubspec.yaml index ed95a47b..85d72d76 100644 --- a/simple_blocs/pubspec.yaml +++ b/simple_blocs/pubspec.yaml @@ -1,14 +1,20 @@ name: simple_blocs description: The Business Logic Components for a Todo App - Simplfied +version: 1.0.0 +publish_to: "none" environment: - sdk: '>=2.0.0-dev.28.0 <3.0.0' + sdk: ^3.9.0 dependencies: + collection: ^1.15.0 + meta: ^1.15.0 + rxdart: ^0.28.0 todos_repository_core: path: ../todos_repository_core - rxdart: ^0.23.1 dev_dependencies: - test: - mockito: + build_runner: ^2.4.13 + lints: ^6.0.0 + test: ^1.25.6 + mockito: ^5.5.0 diff --git a/simple_blocs/test/all_tests.dart b/simple_blocs/test/all_tests.dart deleted file mode 100644 index 1e2f2f2d..00000000 --- a/simple_blocs/test/all_tests.dart +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'stats_bloc_test.dart' as stats_bloc_test; -import 'todo_bloc_test.dart' as todo_bloc_test; -import 'todos_bloc_test.dart' as todos_bloc_test; -import 'todos_interactor_test.dart' as todos_interactor_test; - -void main() { - stats_bloc_test.main(); - todo_bloc_test.main(); - todos_bloc_test.main(); - todos_interactor_test.main(); -} diff --git a/simple_blocs/test/stats_bloc_test.dart b/simple_blocs/test/stats_bloc_test.dart index 765a4e5d..e72bf8b8 100644 --- a/simple_blocs/test/stats_bloc_test.dart +++ b/simple_blocs/test/stats_bloc_test.dart @@ -1,23 +1,18 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:rxdart/rxdart.dart'; import 'package:simple_blocs/simple_blocs.dart'; import 'package:test/test.dart'; -class MockTodosInteractor extends Mock implements TodosInteractor {} +import 'stats_bloc_test.mocks.dart'; +@GenerateNiceMocks([MockSpec()]) void main() { group('StatsBloc', () { test('should stream the number of active todos', () { final interactor = MockTodosInteractor(); final bloc = StatsBloc(interactor); - final todos = [ - Todo('Hallo', complete: true), - Todo('Friend'), - ]; + final todos = [Todo('Hallo', complete: true), Todo('Friend')]; final source = BehaviorSubject>.seeded(todos); when(interactor.todos).thenAnswer((_) => source.stream); diff --git a/simple_blocs/test/stats_bloc_test.mocks.dart b/simple_blocs/test/stats_bloc_test.mocks.dart new file mode 100644 index 00000000..4767ab7e --- /dev/null +++ b/simple_blocs/test/stats_bloc_test.mocks.dart @@ -0,0 +1,133 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in simple_blocs/test/stats_bloc_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:simple_blocs/simple_blocs.dart' as _i3; +import 'package:todos_repository_core/todos_repository_core.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeReactiveTodosRepository_0 extends _i1.SmartFake + implements _i2.ReactiveTodosRepository { + _FakeReactiveTodosRepository_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [TodosInteractor]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodosInteractor extends _i1.Mock implements _i3.TodosInteractor { + @override + _i2.ReactiveTodosRepository get repository => + (super.noSuchMethod( + Invocation.getter(#repository), + returnValue: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + returnValueForMissingStub: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + ) + as _i2.ReactiveTodosRepository); + + @override + _i4.Stream> get todos => + (super.noSuchMethod( + Invocation.getter(#todos), + returnValue: _i4.Stream>.empty(), + returnValueForMissingStub: _i4.Stream>.empty(), + ) + as _i4.Stream>); + + @override + _i4.Stream get allComplete => + (super.noSuchMethod( + Invocation.getter(#allComplete), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream get hasCompletedTodos => + (super.noSuchMethod( + Invocation.getter(#hasCompletedTodos), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream<_i3.Todo> todo(String? id) => + (super.noSuchMethod( + Invocation.method(#todo, [id]), + returnValue: _i4.Stream<_i3.Todo>.empty(), + returnValueForMissingStub: _i4.Stream<_i3.Todo>.empty(), + ) + as _i4.Stream<_i3.Todo>); + + @override + _i4.Future updateTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future addNewTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future deleteTodo(String? id) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [id]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future clearCompleted([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#clearCompleted, [_0]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future> toggleAll([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#toggleAll, [_0]), + returnValue: _i4.Future>.value([]), + returnValueForMissingStub: _i4.Future>.value( + [], + ), + ) + as _i4.Future>); +} diff --git a/simple_blocs/test/todo_bloc_test.dart b/simple_blocs/test/todo_bloc_test.dart index 7f343787..3781f10c 100644 --- a/simple_blocs/test/todo_bloc_test.dart +++ b/simple_blocs/test/todo_bloc_test.dart @@ -1,12 +1,13 @@ import 'dart:async'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:simple_blocs/simple_blocs.dart'; -import 'package:simple_blocs/src/models/models.dart'; import 'package:test/test.dart'; -class MockTodosInteractor extends Mock implements TodosInteractor {} +import 'todo_bloc_test.mocks.dart'; +@GenerateNiceMocks([MockSpec()]) void main() { group('TodoBloc', () { test('should get the todo from the interactor', () { diff --git a/simple_blocs/test/todo_bloc_test.mocks.dart b/simple_blocs/test/todo_bloc_test.mocks.dart new file mode 100644 index 00000000..f42433c7 --- /dev/null +++ b/simple_blocs/test/todo_bloc_test.mocks.dart @@ -0,0 +1,133 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in simple_blocs/test/todo_bloc_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:simple_blocs/simple_blocs.dart' as _i3; +import 'package:todos_repository_core/todos_repository_core.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeReactiveTodosRepository_0 extends _i1.SmartFake + implements _i2.ReactiveTodosRepository { + _FakeReactiveTodosRepository_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [TodosInteractor]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodosInteractor extends _i1.Mock implements _i3.TodosInteractor { + @override + _i2.ReactiveTodosRepository get repository => + (super.noSuchMethod( + Invocation.getter(#repository), + returnValue: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + returnValueForMissingStub: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + ) + as _i2.ReactiveTodosRepository); + + @override + _i4.Stream> get todos => + (super.noSuchMethod( + Invocation.getter(#todos), + returnValue: _i4.Stream>.empty(), + returnValueForMissingStub: _i4.Stream>.empty(), + ) + as _i4.Stream>); + + @override + _i4.Stream get allComplete => + (super.noSuchMethod( + Invocation.getter(#allComplete), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream get hasCompletedTodos => + (super.noSuchMethod( + Invocation.getter(#hasCompletedTodos), + returnValue: _i4.Stream.empty(), + returnValueForMissingStub: _i4.Stream.empty(), + ) + as _i4.Stream); + + @override + _i4.Stream<_i3.Todo> todo(String? id) => + (super.noSuchMethod( + Invocation.method(#todo, [id]), + returnValue: _i4.Stream<_i3.Todo>.empty(), + returnValueForMissingStub: _i4.Stream<_i3.Todo>.empty(), + ) + as _i4.Stream<_i3.Todo>); + + @override + _i4.Future updateTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future addNewTodo(_i3.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future deleteTodo(String? id) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [id]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future clearCompleted([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#clearCompleted, [_0]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future> toggleAll([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#toggleAll, [_0]), + returnValue: _i4.Future>.value([]), + returnValueForMissingStub: _i4.Future>.value( + [], + ), + ) + as _i4.Future>); +} diff --git a/simple_blocs/test/todos_bloc_test.dart b/simple_blocs/test/todos_bloc_test.dart index 453a23ed..533e97a6 100644 --- a/simple_blocs/test/todos_bloc_test.dart +++ b/simple_blocs/test/todos_bloc_test.dart @@ -1,20 +1,21 @@ import 'dart:async'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:simple_blocs/simple_blocs.dart'; -import 'package:simple_blocs/src/models/models.dart'; import 'package:test/test.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; -class MockReactiveTodosRepository extends Mock - implements ReactiveTodosRepository {} - -class MockTodosListInteractor extends Mock implements TodosInteractor {} +import 'todos_bloc_test.mocks.dart'; +@GenerateNiceMocks([ + MockSpec(), + MockSpec(), +]) void main() { group('TodosListBloc', () { test('should display all todos by default', () { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); final bloc = TodosListBloc(interactor); final todos = [Todo('Hallo')]; @@ -24,78 +25,64 @@ void main() { }); test('should display completed todos', () { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); final bloc = TodosListBloc(interactor); - final todos = [ - Todo('Hallo'), - Todo('Friend', complete: true), - ]; + final todos = [Todo('Hallo'), Todo('Friend', complete: true)]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); bloc.updateFilter(VisibilityFilter.completed); - expect( - bloc.visibleTodos, - emitsThrough([todos.last]), - ); + expect(bloc.visibleTodos, emitsThrough([todos.last])); }); test('should display active todos', () { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); final bloc = TodosListBloc(interactor); - final todos = [ - Todo('Hallo'), - Todo('Friend', complete: true), - ]; + final todos = [Todo('Hallo'), Todo('Friend', complete: true)]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); bloc.updateFilter(VisibilityFilter.active); - expect( - bloc.visibleTodos, - emitsThrough([todos.first]), - ); + expect(bloc.visibleTodos, emitsThrough([todos.first])); }); test('should stream the current visibility filter', () { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); final bloc = TodosListBloc(interactor); - final todos = [ - Todo('Hallo'), - Todo('Friend', complete: true), - ]; + final todos = [Todo('Hallo'), Todo('Friend', complete: true)]; when(interactor.todos).thenAnswer((_) => Stream.fromIterable([todos])); bloc.updateFilter(VisibilityFilter.completed); - expect( - bloc.activeFilter, - emits(VisibilityFilter.completed), - ); + expect(bloc.activeFilter, emits(VisibilityFilter.completed)); }); test('allComplete should stream from the interactor', () { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); final bloc = TodosListBloc(interactor); - when(interactor.todos) - .thenAnswer((_) => Stream>.fromIterable([[]])); - when(interactor.allComplete) - .thenAnswer((_) => Stream.fromIterable([false])); + when( + interactor.todos, + ).thenAnswer((_) => Stream>.fromIterable([[]])); + when( + interactor.allComplete, + ).thenAnswer((_) => Stream.fromIterable([false])); expect(bloc.allComplete, emits(false)); }); test('hasCompletedTodos should stream from the interactor', () { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); - when(interactor.todos) - .thenAnswer((_) => Stream>.fromIterable([[]])); - when(interactor.hasCompletedTodos) - .thenAnswer((_) => Stream.fromIterable([true])); + when( + interactor.todos, + ).thenAnswer((_) => Stream>.fromIterable([[]])); + when( + interactor.hasCompletedTodos, + ).thenAnswer((_) => Stream.fromIterable([true])); final bloc = TodosListBloc(interactor); @@ -103,12 +90,14 @@ void main() { }); test('should add todos to the interactor', () async { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); final todo = Todo('AddMe'); - when(interactor.todos).thenAnswer((_) => Stream.fromIterable([ - [todo] - ])); + when(interactor.todos).thenAnswer( + (_) => Stream.fromIterable([ + [todo], + ]), + ); when(interactor.addNewTodo(todo)).thenAnswer((_) => Future.value()); final bloc = TodosListBloc(interactor); @@ -118,10 +107,11 @@ void main() { }); test('should send deletions to the interactor', () async { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); - when(interactor.todos) - .thenAnswer((_) => Stream>.fromIterable([[]])); + when( + interactor.todos, + ).thenAnswer((_) => Stream>.fromIterable([[]])); when(interactor.deleteTodo('1')).thenAnswer((_) => Future.value()); final bloc = TodosListBloc(interactor); @@ -131,10 +121,11 @@ void main() { }); test('should remove completed todos from the interactor', () async { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); - when(interactor.todos) - .thenAnswer((_) => Stream>.fromIterable([[]])); + when( + interactor.todos, + ).thenAnswer((_) => Stream>.fromIterable([[]])); when(interactor.clearCompleted(null)).thenAnswer((_) => Future.value()); final bloc = TodosListBloc(interactor); @@ -144,12 +135,12 @@ void main() { }); test('should toggle all with the interactor', () async { - final interactor = MockTodosListInteractor(); + final interactor = MockTodosInteractor(); - when(interactor.todos) - .thenAnswer((_) => Stream>.fromIterable([[]])); - when(interactor.toggleAll(null)) - .thenAnswer((_) => Future>.value()); + when( + interactor.todos, + ).thenAnswer((_) => Stream>.fromIterable([[]])); + when(interactor.toggleAll(null)).thenAnswer((_) async => []); final bloc = TodosListBloc(interactor); bloc.toggleAll(); diff --git a/simple_blocs/test/todos_bloc_test.mocks.dart b/simple_blocs/test/todos_bloc_test.mocks.dart new file mode 100644 index 00000000..4be9183b --- /dev/null +++ b/simple_blocs/test/todos_bloc_test.mocks.dart @@ -0,0 +1,176 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in simple_blocs/test/todos_bloc_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:simple_blocs/simple_blocs.dart' as _i5; +import 'package:todos_repository_core/src/todo_entity.dart' as _i4; +import 'package:todos_repository_core/todos_repository_core.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeReactiveTodosRepository_0 extends _i1.SmartFake + implements _i2.ReactiveTodosRepository { + _FakeReactiveTodosRepository_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [ReactiveTodosRepository]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockReactiveTodosRepository extends _i1.Mock + implements _i2.ReactiveTodosRepository { + @override + _i3.Future addNewTodo(_i4.TodoEntity? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future deleteTodo(List? idList) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [idList]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Stream> todos() => + (super.noSuchMethod( + Invocation.method(#todos, []), + returnValue: _i3.Stream>.empty(), + returnValueForMissingStub: _i3.Stream>.empty(), + ) + as _i3.Stream>); + + @override + _i3.Future updateTodo(_i4.TodoEntity? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); +} + +/// A class which mocks [TodosInteractor]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodosInteractor extends _i1.Mock implements _i5.TodosInteractor { + @override + _i2.ReactiveTodosRepository get repository => + (super.noSuchMethod( + Invocation.getter(#repository), + returnValue: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + returnValueForMissingStub: _FakeReactiveTodosRepository_0( + this, + Invocation.getter(#repository), + ), + ) + as _i2.ReactiveTodosRepository); + + @override + _i3.Stream> get todos => + (super.noSuchMethod( + Invocation.getter(#todos), + returnValue: _i3.Stream>.empty(), + returnValueForMissingStub: _i3.Stream>.empty(), + ) + as _i3.Stream>); + + @override + _i3.Stream get allComplete => + (super.noSuchMethod( + Invocation.getter(#allComplete), + returnValue: _i3.Stream.empty(), + returnValueForMissingStub: _i3.Stream.empty(), + ) + as _i3.Stream); + + @override + _i3.Stream get hasCompletedTodos => + (super.noSuchMethod( + Invocation.getter(#hasCompletedTodos), + returnValue: _i3.Stream.empty(), + returnValueForMissingStub: _i3.Stream.empty(), + ) + as _i3.Stream); + + @override + _i3.Stream<_i5.Todo> todo(String? id) => + (super.noSuchMethod( + Invocation.method(#todo, [id]), + returnValue: _i3.Stream<_i5.Todo>.empty(), + returnValueForMissingStub: _i3.Stream<_i5.Todo>.empty(), + ) + as _i3.Stream<_i5.Todo>); + + @override + _i3.Future updateTodo(_i5.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future addNewTodo(_i5.Todo? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future deleteTodo(String? id) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [id]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future clearCompleted([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#clearCompleted, [_0]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future> toggleAll([dynamic _0]) => + (super.noSuchMethod( + Invocation.method(#toggleAll, [_0]), + returnValue: _i3.Future>.value([]), + returnValueForMissingStub: _i3.Future>.value( + [], + ), + ) + as _i3.Future>); +} diff --git a/simple_blocs/test/todos_interactor_test.dart b/simple_blocs/test/todos_interactor_test.dart index 9e372f1c..e9eb89a8 100644 --- a/simple_blocs/test/todos_interactor_test.dart +++ b/simple_blocs/test/todos_interactor_test.dart @@ -1,18 +1,15 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:rxdart/rxdart.dart'; import 'package:simple_blocs/simple_blocs.dart'; import 'package:test/test.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; -class MockReactiveTodosRepository extends Mock - implements ReactiveTodosRepository {} +import 'todos_interactor_test.mocks.dart'; +@GenerateNiceMocks([MockSpec()]) void main() { group('TodosListInteractor', () { test('should convert repo entities into Todos', () { @@ -95,8 +92,9 @@ void main() { final todo = Todo("AddMe"); when(repository.todos()).thenAnswer((_) => Stream.empty()); - when(repository.addNewTodo(todo.toEntity())) - .thenAnswer((_) => Future.value()); + when( + repository.addNewTodo(todo.toEntity()), + ).thenAnswer((_) => Future.value()); interactor.addNewTodo(todo); @@ -144,8 +142,9 @@ void main() { ); when(repository.todos()).thenAnswer((_) => source.stream); - when(repository.updateTodo(e1Update)) - .thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e1Update), + ).thenAnswer((_) => Future.sync(() {})); await interactor.toggleAll(null); @@ -166,10 +165,12 @@ void main() { ); when(repository.todos()).thenAnswer((_) => source.stream); - when(repository.updateTodo(e1Update)) - .thenAnswer((_) => Future.sync(() {})); - when(repository.updateTodo(e2Update)) - .thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e1Update), + ).thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e2Update), + ).thenAnswer((_) => Future.sync(() {})); await interactor.toggleAll(null); @@ -191,10 +192,12 @@ void main() { ); when(repository.todos()).thenAnswer((_) => source.stream); - when(repository.updateTodo(e1Update)) - .thenAnswer((_) => Future.sync(() {})); - when(repository.updateTodo(e2Update)) - .thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e1Update), + ).thenAnswer((_) => Future.sync(() {})); + when( + repository.updateTodo(e2Update), + ).thenAnswer((_) => Future.sync(() {})); await interactor.toggleAll(null); diff --git a/simple_blocs/test/todos_interactor_test.mocks.dart b/simple_blocs/test/todos_interactor_test.mocks.dart new file mode 100644 index 00000000..cca76ee1 --- /dev/null +++ b/simple_blocs/test/todos_interactor_test.mocks.dart @@ -0,0 +1,66 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in simple_blocs/test/todos_interactor_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:todos_repository_core/src/reactive_repository.dart' as _i2; +import 'package:todos_repository_core/src/todo_entity.dart' as _i4; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +/// A class which mocks [ReactiveTodosRepository]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockReactiveTodosRepository extends _i1.Mock + implements _i2.ReactiveTodosRepository { + @override + _i3.Future addNewTodo(_i4.TodoEntity? todo) => + (super.noSuchMethod( + Invocation.method(#addNewTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Future deleteTodo(List? idList) => + (super.noSuchMethod( + Invocation.method(#deleteTodo, [idList]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); + + @override + _i3.Stream> todos() => + (super.noSuchMethod( + Invocation.method(#todos, []), + returnValue: _i3.Stream>.empty(), + returnValueForMissingStub: _i3.Stream>.empty(), + ) + as _i3.Stream>); + + @override + _i3.Future updateTodo(_i4.TodoEntity? todo) => + (super.noSuchMethod( + Invocation.method(#updateTodo, [todo]), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) + as _i3.Future); +} diff --git a/states_rebuilder/.gitignore b/states_rebuilder/.gitignore deleted file mode 100644 index ae1f1838..00000000 --- a/states_rebuilder/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# 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 -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Web related -lib/generated_plugin_registrant.dart - -# Exceptions to above rules. -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/states_rebuilder/.metadata b/states_rebuilder/.metadata deleted file mode 100644 index b869ae45..00000000 --- a/states_rebuilder/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 659dc8129d4edb9166e9a0d600439d135740933f - channel: dev - -project_type: app diff --git a/states_rebuilder/.vscode/settings.json b/states_rebuilder/.vscode/settings.json deleted file mode 100644 index eae28263..00000000 --- a/states_rebuilder/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "cSpell.words": [ - "todos" - ] -} \ No newline at end of file diff --git a/states_rebuilder/README.md b/states_rebuilder/README.md deleted file mode 100644 index 7b65b4b4..00000000 --- a/states_rebuilder/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# states_rebuilder_sample - -This sample is an implementation of the todoMVC app using `states_rebuilder` package as a state management technique. - -For more information and tutorials on how states_rebuilder work please check out the [official documentation](https://github.com/GIfatahTH/states_rebuilder). - -# key concepts of the architecture - -* The app is divided into there layers in the form of onion layers : the innermost is Domain, the middle is Service, and the outer layer for UI and external services which has three parts (UI, data_source, and infrastructure). - -The folders structure is : - -```lib - - |-domain - | |-entities - | |-exceptions - |-service (application service) - | |-interfaces (to be implemented by data_source) - | |-exceptions - | |-common - |-data_source - |-ui - | |-pages - | |-exceptions (handle exception) - | |-common -``` - -## domain -Contains enterprise wide business logic. It encapsulates entities, value_objects, exceptions. In case of todoMVC we need one entity `Todo`. - -* Entity is a mutable object with an ID. It should contain all the logic It controls. Entity is validated just before persistance, ie, in toMap() method. - -* Domain objects must throw exceptions defined in the exception folders: - -## service -Contains service application use cases business logic. It defines a set of API to be consumed by the outer layer (UI and infrastructure). -* Service layer defines a set of interfaces, outer layer (data_source and infrastructure) must implement. - -* Service objects must throw exceptions defined in the exception folder in the service layer: - - ->Domain and Service layer are the core portable part of your app. It does not depend on any concrete implementation of external service (data_source) and can be share a cross many UI frameworks. - - -# key concepts of states_rebuilder - -1. With states_rebuilder you can achieve a clear separation between UI and business logic; -2. Your business logic is made up of pure dart classes without the need to refer to external packages or frameworks (NO extension, NO notification, NO annotation); -```dart -class Foo { - //Vanilla dart class - //NO inheritance form external libraries - //NO notification - //No annotation -} -``` -3. You make a singleton of your logical class available to the widget tree by injecting it using the Injector widget. -```dart -Injector( - inject : [Inject(()=>Foo())] - builder : (context) => MyChildWidget() -) -``` -Injector is a StatefulWidget. It can be used any where in the widget tree. -4. From any child widget of the Injector widget, you can get the registered raw singleton using the static method `Injector.get()` method; -```dart -final Foo foo = Injector.get(); -``` -5. To get the registered singleton wrapped with a reactive environment, you use the static method -`Injector.getAsReactive()` method: -```dart -final ReactiveModel foo = Injector.getAsReactive(); -``` -In fact, for each injected model, states_rebuilder registers two singletons: -- The raw singleton of the model -- The reactive singleton of the model which is the raw singleton wrapped with a reactive environment: -The reactive environment adds getters, fields, and methods to modify the state, track the state of the reactive environment and notify the widgets which are subscribed to it. -6. To subscribe a widget as observer, we use `StateBuilder` widget or define the context parameter in `Injector.getAsReactive(context:context)`. -7. The `setState` method is where actions that mutate the state and send notifications are defined. -What happens is that from the user interface, we use the `setState` method to mutate the state and notify subscribed widgets after the state mutation. In the `setState`, we can define a callback for all the side effects to be executed after the state change and just before rebuilding subscribed widgets using `onSetState`, `onData` and `onError` parameter(or `onRebuild` so that the code executes after the reconstruction). From inside `onSetState`, we can call another `setState` to mutate the state and notify the user interface with another call `onSetState` (`onRebuild`) and so on … - -For more information and tutorials on how states_rebuilder work please check out the [official documentation](https://github.com/GIfatahTH/states_rebuilder). \ No newline at end of file diff --git a/states_rebuilder/android/.gitignore b/states_rebuilder/android/.gitignore deleted file mode 100644 index bc2100d8..00000000 --- a/states_rebuilder/android/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java diff --git a/states_rebuilder/android/app/build.gradle b/states_rebuilder/android/app/build.gradle deleted file mode 100644 index 7412815e..00000000 --- a/states_rebuilder/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.states_rebuilder_sample" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/states_rebuilder/android/app/src/debug/AndroidManifest.xml b/states_rebuilder/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index fc323d3f..00000000 --- a/states_rebuilder/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/states_rebuilder/android/app/src/main/AndroidManifest.xml b/states_rebuilder/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 6c2ada0f..00000000 --- a/states_rebuilder/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - diff --git a/states_rebuilder/android/app/src/main/kotlin/com/example/states_rebuilder_sample/MainActivity.kt b/states_rebuilder/android/app/src/main/kotlin/com/example/states_rebuilder_sample/MainActivity.kt deleted file mode 100644 index 71069cbf..00000000 --- a/states_rebuilder/android/app/src/main/kotlin/com/example/states_rebuilder_sample/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.states_rebuilder_sample - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/states_rebuilder/android/app/src/main/res/drawable/launch_background.xml b/states_rebuilder/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/states_rebuilder/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/states_rebuilder/android/app/src/main/res/values/styles.xml b/states_rebuilder/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 00fa4417..00000000 --- a/states_rebuilder/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/states_rebuilder/android/app/src/profile/AndroidManifest.xml b/states_rebuilder/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index fc323d3f..00000000 --- a/states_rebuilder/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/states_rebuilder/android/build.gradle b/states_rebuilder/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/states_rebuilder/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/states_rebuilder/android/gradle.properties b/states_rebuilder/android/gradle.properties deleted file mode 100644 index 38c8d454..00000000 --- a/states_rebuilder/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true -android.useAndroidX=true -android.enableJetifier=true diff --git a/states_rebuilder/android/gradle/wrapper/gradle-wrapper.properties b/states_rebuilder/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 296b146b..00000000 --- a/states_rebuilder/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/states_rebuilder/android/settings.gradle b/states_rebuilder/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/states_rebuilder/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/states_rebuilder/ios/.gitignore b/states_rebuilder/ios/.gitignore deleted file mode 100644 index e96ef602..00000000 --- a/states_rebuilder/ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/states_rebuilder/ios/Flutter/AppFrameworkInfo.plist b/states_rebuilder/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6b4c0f78..00000000 --- a/states_rebuilder/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/states_rebuilder/ios/Flutter/Debug.xcconfig b/states_rebuilder/ios/Flutter/Debug.xcconfig deleted file mode 100644 index 592ceee8..00000000 --- a/states_rebuilder/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/states_rebuilder/ios/Flutter/Release.xcconfig b/states_rebuilder/ios/Flutter/Release.xcconfig deleted file mode 100644 index 592ceee8..00000000 --- a/states_rebuilder/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/states_rebuilder/ios/Runner.xcodeproj/project.pbxproj b/states_rebuilder/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 1c6a7621..00000000 --- a/states_rebuilder/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,518 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.statesRebuilderSample; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.statesRebuilderSample; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.statesRebuilderSample; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/states_rebuilder/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/states_rebuilder/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/states_rebuilder/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/states_rebuilder/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/states_rebuilder/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140cf..00000000 --- a/states_rebuilder/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/states_rebuilder/ios/Runner.xcworkspace/contents.xcworkspacedata b/states_rebuilder/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/states_rebuilder/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/states_rebuilder/ios/Runner/AppDelegate.swift b/states_rebuilder/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a..00000000 --- a/states_rebuilder/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 28c6bf03..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 2ccbfd96..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cde1211..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index dcdc2306..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 2ccbfd96..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b860..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b860..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d3..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 6a84f41e..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index d0e1f585..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2f..00000000 --- a/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/states_rebuilder/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -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. \ No newline at end of file diff --git a/states_rebuilder/ios/Runner/Base.lproj/LaunchScreen.storyboard b/states_rebuilder/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/states_rebuilder/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/states_rebuilder/ios/Runner/Base.lproj/Main.storyboard b/states_rebuilder/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/states_rebuilder/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/states_rebuilder/ios/Runner/Info.plist b/states_rebuilder/ios/Runner/Info.plist deleted file mode 100644 index ca212ede..00000000 --- a/states_rebuilder/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - states_rebuilder_sample - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/states_rebuilder/lib/app.dart b/states_rebuilder/lib/app.dart deleted file mode 100644 index 83ea8fcb..00000000 --- a/states_rebuilder/lib/app.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:states_rebuilder/states_rebuilder.dart'; -import 'package:todos_app_core/todos_app_core.dart'; -import 'data_source/todo_repository.dart'; -import 'localization.dart'; -import 'service/todos_service.dart'; -import 'ui/pages/add_edit_screen.dart/add_edit_screen.dart'; -import 'ui/pages/home_screen/home_screen.dart'; - -class StatesRebuilderApp extends StatelessWidget { - final StatesBuilderTodosRepository repository; - - const StatesRebuilderApp({Key key, this.repository}) : super(key: key); - - @override - Widget build(BuildContext context) { - //Injecting the TodoService globally before MaterialApp widget. - //It will be available throughout all the widget tree even after navigation. - return Injector( - inject: [Inject(() => TodosService(repository))], - builder: (_) => MaterialApp( - title: StatesRebuilderLocalizations().appTitle, - theme: ArchSampleTheme.theme, - localizationsDelegates: [ - ArchSampleLocalizationsDelegate(), - StatesRebuilderLocalizationsDelegate(), - ], - routes: { - ArchSampleRoutes.home: (context) => HomeScreen(), - ArchSampleRoutes.addTodo: (context) => AddEditPage(), - }, - ), - ); - } -} diff --git a/states_rebuilder/lib/data_source/todo_repository.dart b/states_rebuilder/lib/data_source/todo_repository.dart deleted file mode 100644 index d215055e..00000000 --- a/states_rebuilder/lib/data_source/todo_repository.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:todos_repository_core/src/todo_entity.dart'; -import 'package:todos_repository_core/src/todos_repository.dart' as core; -import '../domain/entities/todo.dart'; -import '../service/exceptions/persistance_exception.dart'; -import '../service/interfaces/i_todo_repository.dart'; - -class StatesBuilderTodosRepository implements ITodosRepository { - final core.TodosRepository _todosRepository; - - StatesBuilderTodosRepository({core.TodosRepository todosRepository}) - : _todosRepository = todosRepository; - - @override - Future> loadTodos() async { - try { - final todoEntities = await _todosRepository.loadTodos(); - var todos = []; - for (var todoEntity in todoEntities) { - todos.add( - Todo.fromJson(todoEntity.toJson()), - ); - } - return todos; - } catch (e) { - throw PersistanceException('There is a problem in loading todos : $e'); - } - } - - @override - Future saveTodos(List todos) { - try { - var todosEntities = []; - for (var todo in todos) { - todosEntities.add(TodoEntity.fromJson(todo.toJson())); - } - - return _todosRepository.saveTodos(todosEntities); - } catch (e) { - throw PersistanceException('There is a problem in saving todos : $e'); - } - } -} diff --git a/states_rebuilder/lib/domain/entities/todo.dart b/states_rebuilder/lib/domain/entities/todo.dart deleted file mode 100644 index c149058b..00000000 --- a/states_rebuilder/lib/domain/entities/todo.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:todos_app_core/todos_app_core.dart' as flutter_arch_sample_app; - -import '../exceptions/validation_exception.dart'; - -//Entity is a mutable object with an ID. It should contain all the logic It controls. -//Entity is validated just before persistance, ie, in toMap() method. -class Todo { - String id; - bool complete; - String note; - String task; - - Todo(this.task, {String id, this.note, this.complete = false}) - : id = id ?? flutter_arch_sample_app.Uuid().generateV4(); - - Todo.fromJson(Map map) { - id = map['id'] as String; - task = map['task'] as String; - note = map['note'] as String; - complete = map['complete'] as bool; - } - - // toJson is called just before persistance. - Map toJson() { - _validation(); - return { - 'complete': complete, - 'task': task, - 'note': note, - 'id': id, - }; - } - - void _validation() { - if (id == null) { - // Custom defined error classes - throw ValidationException('This todo has no ID!'); - } - if (task == null || task.isEmpty) { - throw ValidationException('Empty task are not allowed'); - } - } - - @override - int get hashCode => id.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is Todo && runtimeType == other.runtimeType && id == other.id; -} diff --git a/states_rebuilder/lib/domain/exceptions/validation_exception.dart b/states_rebuilder/lib/domain/exceptions/validation_exception.dart deleted file mode 100644 index e348fcd7..00000000 --- a/states_rebuilder/lib/domain/exceptions/validation_exception.dart +++ /dev/null @@ -1,5 +0,0 @@ -class ValidationException extends Error { - final String message; - - ValidationException(this.message); -} diff --git a/states_rebuilder/lib/localization.dart b/states_rebuilder/lib/localization.dart deleted file mode 100644 index e39cd72b..00000000 --- a/states_rebuilder/lib/localization.dart +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter/material.dart'; - -class StatesRebuilderLocalizations { - static StatesRebuilderLocalizations of(BuildContext context) { - return Localizations.of( - context, - StatesRebuilderLocalizations, - ); - } - - String get appTitle => 'States_rebuilder Example'; -} - -class StatesRebuilderLocalizationsDelegate - extends LocalizationsDelegate { - @override - Future load(Locale locale) => - Future(() => StatesRebuilderLocalizations()); - - @override - bool shouldReload(StatesRebuilderLocalizationsDelegate old) => false; - - @override - bool isSupported(Locale locale) => - locale.languageCode.toLowerCase().contains('en'); -} diff --git a/states_rebuilder/lib/main.dart b/states_rebuilder/lib/main.dart deleted file mode 100644 index 63784241..00000000 --- a/states_rebuilder/lib/main.dart +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:key_value_store_flutter/key_value_store_flutter.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -import 'app.dart'; -import 'data_source/todo_repository.dart'; - -void main() async { - WidgetsFlutterBinding.ensureInitialized(); - - runApp( - StatesRebuilderApp( - repository: StatesBuilderTodosRepository( - todosRepository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'states_rebuilder', - FlutterKeyValueStore(await SharedPreferences.getInstance()), - ), - ), - ), - ), - ); -} diff --git a/states_rebuilder/lib/main_web.dart b/states_rebuilder/lib/main_web.dart deleted file mode 100644 index 97eae9a0..00000000 --- a/states_rebuilder/lib/main_web.dart +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:html'; - -import 'package:flutter/material.dart'; -import 'package:key_value_store_web/key_value_store_web.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; - -import 'app.dart'; -import 'data_source/todo_repository.dart'; - -void main() async { - WidgetsFlutterBinding.ensureInitialized(); - runApp( - StatesRebuilderApp( - repository: StatesBuilderTodosRepository( - todosRepository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'states_rebuilder', - WebKeyValueStore(window.localStorage), - ), - ), - ), - ), - ); -} diff --git a/states_rebuilder/lib/service/common/enums.dart b/states_rebuilder/lib/service/common/enums.dart deleted file mode 100644 index d2d209fc..00000000 --- a/states_rebuilder/lib/service/common/enums.dart +++ /dev/null @@ -1,3 +0,0 @@ -enum VisibilityFilter { all, active, completed } - -//NOTE that `AppTab` and `ExtraAction` are not used here. They will be declared in the UI layer. diff --git a/states_rebuilder/lib/service/exceptions/persistance_exception.dart b/states_rebuilder/lib/service/exceptions/persistance_exception.dart deleted file mode 100644 index fdc86d9e..00000000 --- a/states_rebuilder/lib/service/exceptions/persistance_exception.dart +++ /dev/null @@ -1,5 +0,0 @@ -class PersistanceException extends Error { - final String message; - - PersistanceException(this.message); -} diff --git a/states_rebuilder/lib/service/interfaces/i_todo_repository.dart b/states_rebuilder/lib/service/interfaces/i_todo_repository.dart deleted file mode 100644 index 861b0d4d..00000000 --- a/states_rebuilder/lib/service/interfaces/i_todo_repository.dart +++ /dev/null @@ -1,8 +0,0 @@ -import '../../domain/entities/todo.dart'; - -abstract class ITodosRepository { - /// Loads todos - Future> loadTodos(); - // Persists todos to local disk and the web - Future saveTodos(List todos); -} diff --git a/states_rebuilder/lib/service/todos_service.dart b/states_rebuilder/lib/service/todos_service.dart deleted file mode 100644 index 49d80081..00000000 --- a/states_rebuilder/lib/service/todos_service.dart +++ /dev/null @@ -1,73 +0,0 @@ -import 'package:states_rebuilder_sample/domain/entities/todo.dart'; - -import 'common/enums.dart'; -import 'interfaces/i_todo_repository.dart'; - -//`TodosService` is a pure dart class that can be easily tested (see test folder). - -class TodosService { - //Constructor injection of the ITodoRepository abstract class. - TodosService(ITodosRepository todoRepository) - : _todoRepository = todoRepository; - - //private fields - final ITodosRepository _todoRepository; - List _todos = const []; - - //public field - VisibilityFilter activeFilter = VisibilityFilter.all; - - //getters - List get todos { - if (activeFilter == VisibilityFilter.active) { - return _activeTodos; - } - if (activeFilter == VisibilityFilter.completed) { - return _completedTodos; - } - return _todos; - } - - List get _completedTodos => _todos.where((t) => t.complete).toList(); - List get _activeTodos => _todos.where((t) => !t.complete).toList(); - int get numCompleted => _completedTodos.length; - int get numActive => _activeTodos.length; - bool get allComplete => _activeTodos.isEmpty; - - //methods for CRUD - void loadTodos() async { - _todos = await _todoRepository.loadTodos(); - } - - void addTodo(Todo todo) { - _todos.add(todo); - _todoRepository.saveTodos(_todos); - } - - void updateTodo(Todo todo) { - final index = _todos.indexOf(todo); - if (index == -1) return; - _todos[index] = todo; - _todoRepository.saveTodos(_todos); - } - - void deleteTodo(Todo todo) { - if (_todos.remove(todo)) { - _todoRepository.saveTodos(_todos); - } - } - - void toggleAll() { - final allComplete = _todos.every((todo) => todo.complete); - - for (final todo in _todos) { - todo.complete = !allComplete; - } - _todoRepository.saveTodos(_todos); - } - - void clearCompleted() { - _todos.removeWhere((todo) => todo.complete); - _todoRepository.saveTodos(_todos); - } -} diff --git a/states_rebuilder/lib/ui/common/enums.dart b/states_rebuilder/lib/ui/common/enums.dart deleted file mode 100644 index 9fd4c5d6..00000000 --- a/states_rebuilder/lib/ui/common/enums.dart +++ /dev/null @@ -1,2 +0,0 @@ -enum AppTab { todos, stats } -enum ExtraAction { toggleAllComplete, clearCompleted } diff --git a/states_rebuilder/lib/ui/common/helper_methods.dart b/states_rebuilder/lib/ui/common/helper_methods.dart deleted file mode 100644 index eba8136c..00000000 --- a/states_rebuilder/lib/ui/common/helper_methods.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:states_rebuilder/states_rebuilder.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -import '../../domain/entities/todo.dart'; -import '../../service/todos_service.dart'; - -class HelperMethods { - static void removeTodo(Todo todo) { - final todosServiceRM = Injector.getAsReactive(); - todosServiceRM.setState( - (s) => s.deleteTodo(todo), - onSetState: (context) { - Scaffold.of(context).showSnackBar( - SnackBar( - key: ArchSampleKeys.snackbar, - duration: Duration(seconds: 2), - content: Text( - ArchSampleLocalizations.of(context).todoDeleted(todo.task), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - action: SnackBarAction( - label: ArchSampleLocalizations.of(context).undo, - onPressed: () { - todosServiceRM.setState((s) => s.addTodo(todo)); - }, - ), - ), - ); - }, - ); - } -} diff --git a/states_rebuilder/lib/ui/exceptions/error_handler.dart b/states_rebuilder/lib/ui/exceptions/error_handler.dart deleted file mode 100644 index 4be1dc88..00000000 --- a/states_rebuilder/lib/ui/exceptions/error_handler.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:states_rebuilder_sample/domain/exceptions/validation_exception.dart'; -import 'package:states_rebuilder_sample/service/exceptions/persistance_exception.dart'; - -class ErrorHandler { - static String getErrorMessage(dynamic error) { - if (error is ValidationException) { - return error.message; - } - - if (error is PersistanceException) { - return error.message; - } - - throw (error); - } -} diff --git a/states_rebuilder/lib/ui/pages/add_edit_screen.dart/add_edit_screen.dart b/states_rebuilder/lib/ui/pages/add_edit_screen.dart/add_edit_screen.dart deleted file mode 100644 index c3089261..00000000 --- a/states_rebuilder/lib/ui/pages/add_edit_screen.dart/add_edit_screen.dart +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:states_rebuilder/states_rebuilder.dart'; -import 'package:states_rebuilder_sample/domain/entities/todo.dart'; -import 'package:states_rebuilder_sample/service/todos_service.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class AddEditPage extends StatefulWidget { - final Todo todo; - - AddEditPage({ - Key key, - this.todo, - }) : super(key: key ?? ArchSampleKeys.addTodoScreen); - - @override - _AddEditPageState createState() => _AddEditPageState(); -} - -class _AddEditPageState extends State { - static final GlobalKey formKey = GlobalKey(); - // Here we use a StatefulWidget to hold local fields _task and _note - String _task; - String _note; - bool get isEditing => widget.todo != null; - final todosService = Injector.get(); - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(isEditing - ? ArchSampleLocalizations.of(context).editTodo - : ArchSampleLocalizations.of(context).addTodo), - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: Form( - key: formKey, - autovalidate: false, - onWillPop: () { - return Future(() => true); - }, - child: ListView( - children: [ - TextFormField( - initialValue: widget.todo != null ? widget.todo.task : '', - key: ArchSampleKeys.taskField, - autofocus: isEditing ? false : true, - style: Theme.of(context).textTheme.headline, - decoration: InputDecoration( - hintText: ArchSampleLocalizations.of(context).newTodoHint), - validator: (val) => val.trim().isEmpty - ? ArchSampleLocalizations.of(context).emptyTodoError - : null, - onSaved: (value) => _task = value, - ), - TextFormField( - initialValue: widget.todo != null ? widget.todo.note : '', - key: ArchSampleKeys.noteField, - maxLines: 10, - style: Theme.of(context).textTheme.subhead, - decoration: InputDecoration( - hintText: ArchSampleLocalizations.of(context).notesHint, - ), - onSaved: (value) => _note = value, - ) - ], - ), - ), - ), - floatingActionButton: FloatingActionButton( - key: - isEditing ? ArchSampleKeys.saveTodoFab : ArchSampleKeys.saveNewTodo, - tooltip: isEditing - ? ArchSampleLocalizations.of(context).saveChanges - : ArchSampleLocalizations.of(context).addTodo, - child: Icon(isEditing ? Icons.check : Icons.add), - onPressed: () { - final form = formKey.currentState; - if (form.validate()) { - form.save(); - - if (isEditing) { - widget.todo - ..task = _task - ..note = _note; - todosService.updateTodo(widget.todo); - } else { - todosService.addTodo( - Todo( - _task, - note: _note, - ), - ); - } - - Navigator.pop(context); - } - }, - ), - ); - } -} diff --git a/states_rebuilder/lib/ui/pages/detail_screen/detail_screen.dart b/states_rebuilder/lib/ui/pages/detail_screen/detail_screen.dart deleted file mode 100644 index ea3f244b..00000000 --- a/states_rebuilder/lib/ui/pages/detail_screen/detail_screen.dart +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:states_rebuilder/states_rebuilder.dart'; -import 'package:states_rebuilder_sample/domain/entities/todo.dart'; -import 'package:states_rebuilder_sample/service/todos_service.dart'; -import 'package:states_rebuilder_sample/ui/common/helper_methods.dart'; -import 'package:states_rebuilder_sample/ui/pages/add_edit_screen.dart/add_edit_screen.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class DetailScreen extends StatelessWidget { - DetailScreen(this.todo) : super(key: ArchSampleKeys.todoDetailsScreen); - final Todo todo; - //use Injector.get because DetailScreen need not be reactive - final todosService = Injector.get(); - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(ArchSampleLocalizations.of(context).todoDetails), - actions: [ - IconButton( - key: ArchSampleKeys.deleteTodoButton, - tooltip: ArchSampleLocalizations.of(context).deleteTodo, - icon: Icon(Icons.delete), - onPressed: () { - //This is one particularity of states_rebuilder - //We have the ability to call a method form an injected model without notify observers - //This can be done by consuming the injected model using Injector.get and call the method we want. - todosService.deleteTodo(todo); - //When navigating back to home page, rebuild is granted by flutter framework. - Navigator.pop(context, todo); - //delegate to the static method HelperMethods.removeTodo to remove todo - HelperMethods.removeTodo(todo); - }, - ) - ], - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: ListView( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(right: 8.0), - child: StateBuilder( - //getting a new ReactiveModel of TodosService to optimize rebuild of widgets - builder: (_, todosServiceRM) { - return Checkbox( - value: todo.complete, - key: ArchSampleKeys.detailsTodoItemCheckbox, - onChanged: (complete) { - todo.complete = !todo.complete; - //only this checkBox will rebuild - todosServiceRM.setState((s) => s.updateTodo(todo)); - }, - ); - }, - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), - child: Text( - todo.task, - key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, - ), - ), - Text( - todo.note, - key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) - ], - ), - ), - ], - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - tooltip: ArchSampleLocalizations.of(context).editTodo, - child: Icon(Icons.edit), - key: ArchSampleKeys.editTodoFab, - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) { - return AddEditPage( - key: ArchSampleKeys.editTodoScreen, - todo: todo, - ); - }, - ), - ); - }, - ), - ); - } -} diff --git a/states_rebuilder/lib/ui/pages/home_screen/extra_actions_button.dart b/states_rebuilder/lib/ui/pages/home_screen/extra_actions_button.dart deleted file mode 100644 index aca10542..00000000 --- a/states_rebuilder/lib/ui/pages/home_screen/extra_actions_button.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:states_rebuilder/states_rebuilder.dart'; -import 'package:states_rebuilder_sample/service/todos_service.dart'; -import 'package:states_rebuilder_sample/ui/common/enums.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class ExtraActionsButton extends StatelessWidget { - ExtraActionsButton({Key key}) : super(key: key); - final todosServiceRM = Injector.getAsReactive(); - - @override - Widget build(BuildContext context) { - return PopupMenuButton( - key: ArchSampleKeys.extraActionsButton, - onSelected: (action) { - if (action == ExtraAction.toggleAllComplete) { - todosServiceRM.setState((s) => s.toggleAll()); - } else if (action == ExtraAction.clearCompleted) { - todosServiceRM.setState((s) => s.clearCompleted()); - } - }, - itemBuilder: (BuildContext context) { - return >[ - PopupMenuItem( - key: ArchSampleKeys.toggleAll, - value: ExtraAction.toggleAllComplete, - child: Text(todosServiceRM.state.allComplete - ? ArchSampleLocalizations.of(context).markAllIncomplete - : ArchSampleLocalizations.of(context).markAllComplete), - ), - PopupMenuItem( - key: ArchSampleKeys.clearCompleted, - value: ExtraAction.clearCompleted, - child: Text(ArchSampleLocalizations.of(context).clearCompleted), - ), - ]; - }, - ); - } -} diff --git a/states_rebuilder/lib/ui/pages/home_screen/filter_button.dart b/states_rebuilder/lib/ui/pages/home_screen/filter_button.dart deleted file mode 100644 index 0687f5af..00000000 --- a/states_rebuilder/lib/ui/pages/home_screen/filter_button.dart +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:states_rebuilder/states_rebuilder.dart'; -import 'package:states_rebuilder_sample/service/common/enums.dart'; -import 'package:states_rebuilder_sample/service/todos_service.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class FilterButton extends StatelessWidget { - const FilterButton({this.isActive, Key key}) : super(key: key); - final bool isActive; - - @override - Widget build(BuildContext context) { - //context is used to register FilterButton as observer in todosServiceRM - final todosServiceRM = - Injector.getAsReactive(context: context); - - final defaultStyle = Theme.of(context).textTheme.body1; - final activeStyle = Theme.of(context) - .textTheme - .body1 - .copyWith(color: Theme.of(context).accentColor); - final button = _Button( - onSelected: (filter) { - todosServiceRM.setState((s) => s.activeFilter = filter); - }, - activeFilter: todosServiceRM.state.activeFilter, - activeStyle: activeStyle, - defaultStyle: defaultStyle, - ); - - return AnimatedOpacity( - opacity: isActive ? 1.0 : 0.0, - duration: Duration(milliseconds: 150), - child: isActive ? button : IgnorePointer(child: button), - ); - } -} - -class _Button extends StatelessWidget { - const _Button({ - Key key, - @required this.onSelected, - @required this.activeFilter, - @required this.activeStyle, - @required this.defaultStyle, - }) : super(key: key); - - final PopupMenuItemSelected onSelected; - final VisibilityFilter activeFilter; - final TextStyle activeStyle; - final TextStyle defaultStyle; - - @override - Widget build(BuildContext context) { - return PopupMenuButton( - key: ArchSampleKeys.filterButton, - tooltip: ArchSampleLocalizations.of(context).filterTodos, - onSelected: onSelected, - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - key: ArchSampleKeys.allFilter, - value: VisibilityFilter.all, - child: Text( - ArchSampleLocalizations.of(context).showAll, - style: activeFilter == VisibilityFilter.all - ? activeStyle - : defaultStyle, - ), - ), - PopupMenuItem( - key: ArchSampleKeys.activeFilter, - value: VisibilityFilter.active, - child: Text( - ArchSampleLocalizations.of(context).showActive, - style: activeFilter == VisibilityFilter.active - ? activeStyle - : defaultStyle, - ), - ), - PopupMenuItem( - key: ArchSampleKeys.completedFilter, - value: VisibilityFilter.completed, - child: Text( - ArchSampleLocalizations.of(context).showCompleted, - style: activeFilter == VisibilityFilter.completed - ? activeStyle - : defaultStyle, - ), - ), - ], - icon: Icon(Icons.filter_list), - ); - } -} diff --git a/states_rebuilder/lib/ui/pages/home_screen/home_screen.dart b/states_rebuilder/lib/ui/pages/home_screen/home_screen.dart deleted file mode 100644 index 69655b82..00000000 --- a/states_rebuilder/lib/ui/pages/home_screen/home_screen.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:states_rebuilder/states_rebuilder.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -import '../../../localization.dart'; -import '../../../service/todos_service.dart'; -import '../../common/enums.dart'; -import 'extra_actions_button.dart'; -import 'filter_button.dart'; -import 'stats_counter.dart'; -import 'todo_list.dart'; - -class HomeScreen extends StatefulWidget { - HomeScreen({Key key}) : super(key: key ?? ArchSampleKeys.homeScreen); - - @override - _HomeScreenState createState() => _HomeScreenState(); -} - -class _HomeScreenState extends State { - // Here we use a StatefulWidget to store the _activeTab state which is private to this class - - AppTab _activeTab = AppTab.todos; - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(StatesRebuilderLocalizations.of(context).appTitle), - actions: [ - FilterButton(isActive: _activeTab == AppTab.todos), - ExtraActionsButton(), - ], - ), - body: StateBuilder( - models: [Injector.getAsReactive()], - initState: (_, todosServiceRM) { - //update state and notify observer - return todosServiceRM.setState((s) => s.loadTodos()); - }, - builder: (_, todosServiceRM) { - return _activeTab == AppTab.todos ? TodoList() : StatsCounter(); - }, - ), - floatingActionButton: FloatingActionButton( - key: ArchSampleKeys.addTodoFab, - onPressed: () { - Navigator.pushNamed(context, ArchSampleRoutes.addTodo); - }, - child: Icon(Icons.add), - tooltip: ArchSampleLocalizations.of(context).addTodo, - ), - bottomNavigationBar: BottomNavigationBar( - key: ArchSampleKeys.tabs, - currentIndex: AppTab.values.indexOf(_activeTab), - onTap: (index) { - //mutate the state of the private field _activeTab and use Flutter setState because - setState(() => _activeTab = AppTab.values[index]); - }, - items: AppTab.values.map( - (tab) { - return BottomNavigationBarItem( - icon: Icon( - tab == AppTab.todos ? Icons.list : Icons.show_chart, - key: tab == AppTab.stats - ? ArchSampleKeys.statsTab - : ArchSampleKeys.todoTab, - ), - title: Text( - tab == AppTab.stats - ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos, - ), - ); - }, - ).toList(), - ), - ); - } -} diff --git a/states_rebuilder/lib/ui/pages/home_screen/stats_counter.dart b/states_rebuilder/lib/ui/pages/home_screen/stats_counter.dart deleted file mode 100644 index 1b134031..00000000 --- a/states_rebuilder/lib/ui/pages/home_screen/stats_counter.dart +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:states_rebuilder/states_rebuilder.dart'; -import 'package:states_rebuilder_sample/service/todos_service.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class StatsCounter extends StatelessWidget { - //use Injector.get, because this class need not to be reactive and its rebuild is ensured by its parent. - final todosService = Injector.get(); - - StatsCounter() : super(key: ArchSampleKeys.statsCounter); - - @override - Widget build(BuildContext context) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '${todosService.numCompleted}', - key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 8.0), - child: Text( - ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 24.0), - child: Text( - '${todosService.numActive}', - key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, - ), - ) - ], - ), - ); - } -} diff --git a/states_rebuilder/lib/ui/pages/home_screen/todo_item.dart b/states_rebuilder/lib/ui/pages/home_screen/todo_item.dart deleted file mode 100644 index 4091623d..00000000 --- a/states_rebuilder/lib/ui/pages/home_screen/todo_item.dart +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:states_rebuilder/states_rebuilder.dart'; -import 'package:states_rebuilder_sample/domain/entities/todo.dart'; -import 'package:states_rebuilder_sample/service/todos_service.dart'; -import 'package:states_rebuilder_sample/ui/common/helper_methods.dart'; -import 'package:states_rebuilder_sample/ui/pages/detail_screen/detail_screen.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -class TodoItem extends StatelessWidget { - final Todo todo; - - TodoItem({ - Key key, - @required this.todo, - }) : super(key: key); - - final todosServiceRM = Injector.getAsReactive(); - - @override - Widget build(BuildContext context) { - return Dismissible( - key: ArchSampleKeys.todoItem(todo.id), - onDismissed: (direction) { - //delegate removing todo to the static method HelperMethods.removeTodo. - HelperMethods.removeTodo(todo); - }, - child: ListTile( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) { - return DetailScreen(todo); - }, - ), - ); - }, - leading: Checkbox( - key: ArchSampleKeys.todoItemCheckbox(todo.id), - value: todo.complete, - onChanged: (complete) { - todo.complete = !todo.complete; - todosServiceRM.setState((state) => state.updateTodo(todo)); - }, - ), - title: Text( - todo.task, - key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, - ), - subtitle: Text( - todo.note, - key: ArchSampleKeys.todoItemNote(todo.id), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, - ), - ), - ); - } -} diff --git a/states_rebuilder/lib/ui/pages/home_screen/todo_list.dart b/states_rebuilder/lib/ui/pages/home_screen/todo_list.dart deleted file mode 100644 index 449b1ef1..00000000 --- a/states_rebuilder/lib/ui/pages/home_screen/todo_list.dart +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:states_rebuilder/states_rebuilder.dart'; -import 'package:states_rebuilder_sample/service/todos_service.dart'; -import 'package:states_rebuilder_sample/ui/exceptions/error_handler.dart'; -import 'package:todos_app_core/todos_app_core.dart'; - -import 'todo_item.dart'; - -class TodoList extends StatelessWidget { - TodoList() : super(key: ArchSampleKeys.todoList); - final todosServiceRM = Injector.getAsReactive(); - @override - Widget build(BuildContext context) { - //use whenConnectionState method to go through all the possible status of the ReactiveModel - return todosServiceRM.whenConnectionState( - onIdle: () => Container(), - onWaiting: () => Center( - child: CircularProgressIndicator( - key: ArchSampleKeys.todosLoading, - ), - ), - onData: (todosService) { - return ListView.builder( - key: ArchSampleKeys.todoList, - itemCount: todosService.todos.length, - itemBuilder: (BuildContext context, int index) { - final todo = todosService.todos[index]; - return TodoItem(todo: todo); - }, - ); - }, - onError: (error) { - //Delegate error handling to the static method ErrorHandler.getErrorMessage - return Center(child: Text(ErrorHandler.getErrorMessage(error))); - }, - ); - } -} diff --git a/states_rebuilder/pubspec.yaml b/states_rebuilder/pubspec.yaml deleted file mode 100644 index 10e92960..00000000 --- a/states_rebuilder/pubspec.yaml +++ /dev/null @@ -1,86 +0,0 @@ -name: states_rebuilder_sample -description: A new Flutter project. - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 - -environment: - sdk: ">=2.1.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - states_rebuilder: ^1.11.2 - key_value_store_flutter: - key_value_store_web: - shared_preferences: - todos_repository_local_storage: - path: ../todos_repository_local_storage - todos_app_core: - path: ../todos_app_core - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_driver: - sdk: flutter - test: - mockito: - integration_tests: - path: ../integration_tests - - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/states_rebuilder/test/fake_repository.dart b/states_rebuilder/test/fake_repository.dart deleted file mode 100644 index d8fa18ff..00000000 --- a/states_rebuilder/test/fake_repository.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:states_rebuilder_sample/domain/entities/todo.dart'; -import 'package:states_rebuilder_sample/service/interfaces/i_todo_repository.dart'; - -class FakeRepository implements ITodosRepository { - @override - Future> loadTodos() { - return Future.value( - [ - Todo( - 'task1', - id: '1', - note: 'note1', - complete: true, - ), - Todo( - 'task2', - id: '2', - note: 'note2', - complete: false, - ), - ], - ); - } - - bool isSaved = false; - @override - Future saveTodos(List todos) { - isSaved = true; - return Future.value(true); - } -} diff --git a/states_rebuilder/test/todo_service_test.dart b/states_rebuilder/test/todo_service_test.dart deleted file mode 100644 index ae91c27f..00000000 --- a/states_rebuilder/test/todo_service_test.dart +++ /dev/null @@ -1,119 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:states_rebuilder_sample/domain/entities/todo.dart'; -import 'package:states_rebuilder_sample/service/common/enums.dart'; -import 'package:states_rebuilder_sample/service/interfaces/i_todo_repository.dart'; -import 'package:states_rebuilder_sample/service/todos_service.dart'; - -import 'fake_repository.dart'; - -//TodoService class is a pure dart class, you can test it just as you test a plain dart class. -void main() { - group( - 'TodosService', - () { - ITodosRepository todosRepository; - TodosService todoService; - setUp( - () { - todosRepository = FakeRepository(); - todoService = TodosService(todosRepository); - }, - ); - - test( - 'should load todos works', - () async { - expect(todoService.todos.isEmpty, isTrue); - await todoService.loadTodos(); - expect(todoService.todos.length, equals(2)); - }, - ); - - test( - 'should filler todos works', - () async { - await todoService.loadTodos(); - //all todos - expect(todoService.todos.length, equals(2)); - //active todos - todoService.activeFilter = VisibilityFilter.active; - expect(todoService.todos.length, equals(1)); - //completed todos - todoService.activeFilter = VisibilityFilter.completed; - expect(todoService.todos.length, equals(1)); - }, - ); - - test( - 'should add todo works', - () async { - await todoService.loadTodos(); - expect(todoService.todos.length, equals(2)); - final todoToAdd = Todo('addTask'); - await todoService.addTodo(todoToAdd); - expect(todoService.todos.length, equals(3)); - expect(await (todosRepository as FakeRepository).isSaved, isTrue); - }, - ); - - test( - 'should update todo works', - () async { - await todoService.loadTodos(); - final beforeUpdate = - todoService.todos.firstWhere((todo) => todo.id == '1'); - expect(beforeUpdate.task, equals('task1')); - await todoService.updateTodo(Todo('updateTodo', id: '1')); - expect(await (todosRepository as FakeRepository).isSaved, isTrue); - final afterUpdate = - todoService.todos.firstWhere((todo) => todo.id == '1'); - expect(afterUpdate.task, equals('updateTodo')); - }, - ); - - test( - 'should delete todo works', - () async { - await todoService.loadTodos(); - expect(todoService.todos.length, equals(2)); - await todoService.deleteTodo(Todo('updateTodo', id: '1')); - expect(await (todosRepository as FakeRepository).isSaved, isTrue); - expect(todoService.todos.length, equals(1)); - }, - ); - - test( - 'should toggleAll todos works', - () async { - await todoService.loadTodos(); - expect(todoService.numActive, equals(1)); - expect(todoService.numCompleted, equals(1)); - - await todoService.toggleAll(); - expect(await (todosRepository as FakeRepository).isSaved, isTrue); - expect(todoService.numActive, equals(0)); - expect(todoService.numCompleted, equals(2)); - - await todoService.toggleAll(); - expect(todoService.numActive, equals(2)); - expect(todoService.numCompleted, equals(0)); - }, - ); - - test( - 'should clearCompleted todos works', - () async { - await todoService.loadTodos(); - expect(todoService.numActive, equals(1)); - expect(todoService.numCompleted, equals(1)); - - await todoService.clearCompleted(); - expect(await (todosRepository as FakeRepository).isSaved, isTrue); - expect(todoService.todos.length, equals(1)); - expect(todoService.numActive, equals(1)); - expect(todoService.numCompleted, equals(0)); - }, - ); - }, - ); -} diff --git a/states_rebuilder/test_driver/todo_app.dart b/states_rebuilder/test_driver/todo_app.dart deleted file mode 100644 index e3d02f0b..00000000 --- a/states_rebuilder/test_driver/todo_app.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// This line imports the extension -import 'package:flutter_driver/driver_extension.dart'; -import 'package:states_rebuilder_sample/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/states_rebuilder/test_driver/todo_app_test.dart b/states_rebuilder/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/states_rebuilder/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/states_rebuilder/web/index.html b/states_rebuilder/web/index.html deleted file mode 100644 index 929359b3..00000000 --- a/states_rebuilder/web/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - states_rebuilder_sample - - - - - diff --git a/todos_app_core/.flutter-plugins-dependencies b/todos_app_core/.flutter-plugins-dependencies index 8885f09e..54bf628d 100644 --- a/todos_app_core/.flutter-plugins-dependencies +++ b/todos_app_core/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"android":[{"name":"path_provider","path":"/Users/remirousselet/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.0/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":[]}],"date_created":"2020-02-10 11:24:47.749791","version":"1.14.7-pre.38"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"/Users/brian/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"path_provider_android","path":"/Users/brian/.pub-cache/hosted/pub.dev/path_provider_android-2.2.17/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"path_provider_foundation","path":"/Users/brian/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"path_provider_linux","path":"/Users/brian/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"path_provider_windows","path":"/Users/brian/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2025-07-06 22:43:48.361394","version":"3.32.5","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/todos_app_core/lib/src/keys.dart b/todos_app_core/lib/src/keys.dart index 7c088f95..c0319dd0 100644 --- a/todos_app_core/lib/src/keys.dart +++ b/todos_app_core/lib/src/keys.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/widgets.dart'; class ArchSampleKeys { diff --git a/todos_app_core/lib/src/localization.dart b/todos_app_core/lib/src/localization.dart index 642ddac3..624c232c 100644 --- a/todos_app_core/lib/src/localization.dart +++ b/todos_app_core/lib/src/localization.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/widgets.dart'; @@ -22,7 +18,9 @@ class ArchSampleLocalizations { static ArchSampleLocalizations of(BuildContext context) { return Localizations.of( - context, ArchSampleLocalizations); + context, + ArchSampleLocalizations, + )!; } String get todos => Intl.message( diff --git a/todos_app_core/lib/src/localizations/messages_all.dart b/todos_app_core/lib/src/localizations/messages_all.dart index 839d9511..974f8ff2 100644 --- a/todos_app_core/lib/src/localizations/messages_all.dart +++ b/todos_app_core/lib/src/localizations/messages_all.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart // This is a library that looks up messages for specific locales by // delegating to the appropriate library. @@ -20,7 +16,7 @@ Map _deferredLibraries = { 'en': () => Future.value(null), }; -MessageLookupByLibrary _findExact(localeName) { +MessageLookupByLibrary? _findExact(String? localeName) { switch (localeName) { case 'en': return messages_en.messages; @@ -45,9 +41,11 @@ bool _messagesExistFor(String locale) { } } -MessageLookupByLibrary _findGeneratedMessagesFor(locale) { +MessageLookupByLibrary? _findGeneratedMessagesFor(locale) { var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); + if (actualLocale == null) return null; + return _findExact(actualLocale); } diff --git a/todos_app_core/lib/src/localizations/messages_en.dart b/todos_app_core/lib/src/localizations/messages_en.dart index 572069b7..f9e3974d 100644 --- a/todos_app_core/lib/src/localizations/messages_en.dart +++ b/todos_app_core/lib/src/localizations/messages_en.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart // This is a library that provides messages for a en locale. All the // messages from the main program should be duplicated here with the same diff --git a/todos_app_core/lib/src/optional.dart b/todos_app_core/lib/src/optional.dart index 59d8e146..6b2cdbc7 100644 --- a/todos_app_core/lib/src/optional.dart +++ b/todos_app_core/lib/src/optional.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:collection'; /// A value that might be absent. @@ -10,7 +6,7 @@ import 'dart:collection'; /// values to be null. It signals that a value is not required and provides /// convenience methods for dealing with the absent case. class Optional extends IterableBase { - final T _value; + final T? _value; /// Constructs an empty Optional. const Optional.absent() : _value = null; @@ -40,13 +36,13 @@ class Optional extends IterableBase { if (_value == null) { throw StateError('value called on absent Optional.'); } - return _value; + return _value!; } /// Executes a function if the Optional value is present. void ifPresent(void Function(T value) ifPresent) { if (isPresent) { - ifPresent(_value); + ifPresent(_value!); } } @@ -70,7 +66,7 @@ class Optional extends IterableBase { } /// Gets the Optional value, or [null] if there is none. - T get orNull => _value; + T? get orNull => _value; /// Transforms the Optional value. /// @@ -80,12 +76,12 @@ class Optional extends IterableBase { Optional transform(S Function(T value) transformer) { return _value == null ? Optional.absent() - : Optional.of(transformer(_value)); + : Optional.of(transformer(_value!)); } @override Iterator get iterator => - isPresent ? [_value].iterator : Iterable.empty().iterator; + isPresent ? [_value!].iterator : Iterable.empty().iterator; /// Delegates to the underlying [value] hashCode. @override diff --git a/todos_app_core/lib/src/routes.dart b/todos_app_core/lib/src/routes.dart index 1be9f34d..02478c85 100644 --- a/todos_app_core/lib/src/routes.dart +++ b/todos_app_core/lib/src/routes.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - class ArchSampleRoutes { static final home = '/'; static final addTodo = '/addTodo'; diff --git a/todos_app_core/lib/src/theme.dart b/todos_app_core/lib/src/theme.dart index b03c5b87..0e96440a 100644 --- a/todos_app_core/lib/src/theme.dart +++ b/todos_app_core/lib/src/theme.dart @@ -1,32 +1,23 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; class ArchSampleTheme { - static ThemeData get theme { - final themeData = ThemeData.dark(); - final textTheme = themeData.textTheme; - final body1 = textTheme.body1.copyWith(decorationColor: Colors.transparent); - - return ThemeData.dark().copyWith( - primaryColor: Colors.grey[800], - accentColor: Colors.cyan[300], - buttonColor: Colors.grey[800], - textSelectionColor: Colors.cyan[100], - toggleableActiveColor: Colors.cyan[300], - floatingActionButtonTheme: FloatingActionButtonThemeData( - backgroundColor: Colors.cyan[300], - ), - snackBarTheme: SnackBarThemeData( - backgroundColor: themeData.dialogBackgroundColor, - contentTextStyle: body1, - actionTextColor: Colors.cyan[300], + static ThemeData get lightTheme { + return ThemeData.from( + colorScheme: ColorScheme.fromSeed( + seedColor: Colors.cyanAccent, + brightness: Brightness.light, ), - textTheme: textTheme.copyWith( - body1: body1, + useMaterial3: true, + ); + } + + static ThemeData get darkTheme { + return ThemeData.from( + colorScheme: ColorScheme.fromSeed( + seedColor: Colors.cyanAccent, + brightness: Brightness.dark, ), + useMaterial3: true, ); } } diff --git a/todos_app_core/lib/src/uuid.dart b/todos_app_core/lib/src/uuid.dart index 765daa7a..f7c0836d 100644 --- a/todos_app_core/lib/src/uuid.dart +++ b/todos_app_core/lib/src/uuid.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:math'; /// A UUID generator, useful for generating unique IDs for your Todos. diff --git a/todos_app_core/pubspec.yaml b/todos_app_core/pubspec.yaml index e4973028..73b83a26 100644 --- a/todos_app_core/pubspec.yaml +++ b/todos_app_core/pubspec.yaml @@ -1,7 +1,7 @@ name: todos_app_core environment: - sdk: '>=2.0.0-dev.28.0 <3.0.0' + sdk: '>=3.0.0 <4.0.0' dependencies: intl: diff --git a/todos_repository_core/lib/src/reactive_repository.dart b/todos_repository_core/lib/src/reactive_repository.dart index cec6d101..9f1c949e 100644 --- a/todos_repository_core/lib/src/reactive_repository.dart +++ b/todos_repository_core/lib/src/reactive_repository.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; import 'dart:core'; import 'todo_entity.dart'; diff --git a/todos_repository_core/lib/src/todo_entity.dart b/todos_repository_core/lib/src/todo_entity.dart index 56429e66..bf6d3706 100644 --- a/todos_repository_core/lib/src/todo_entity.dart +++ b/todos_repository_core/lib/src/todo_entity.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - class TodoEntity { final bool complete; final String id; @@ -38,7 +34,7 @@ class TodoEntity { return 'TodoEntity{complete: $complete, task: $task, note: $note, id: $id}'; } - static TodoEntity fromJson(Map json) { + static TodoEntity fromJson(Map json) { return TodoEntity( json['task'] as String, json['id'] as String, diff --git a/todos_repository_core/lib/src/todos_repository.dart b/todos_repository_core/lib/src/todos_repository.dart index 364cc9d4..5926223f 100644 --- a/todos_repository_core/lib/src/todos_repository.dart +++ b/todos_repository_core/lib/src/todos_repository.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; import 'dart:core'; import 'todo_entity.dart'; @@ -21,5 +16,5 @@ abstract class TodosRepository { Future> loadTodos(); // Persists todos to local disk and the web - Future saveTodos(List todos); + Future saveTodos(List todos); } diff --git a/todos_repository_core/lib/src/user_entity.dart b/todos_repository_core/lib/src/user_entity.dart index e04d85c3..8ef35bf6 100644 --- a/todos_repository_core/lib/src/user_entity.dart +++ b/todos_repository_core/lib/src/user_entity.dart @@ -1,13 +1,13 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - class UserEntity { final String id; final String displayName; final String photoUrl; - UserEntity({this.id, this.displayName, this.photoUrl}); + UserEntity({ + required this.id, + required this.displayName, + required this.photoUrl, + }); @override bool operator ==(Object other) => diff --git a/todos_repository_core/lib/src/user_repository.dart b/todos_repository_core/lib/src/user_repository.dart index ddac19cc..e5ffd129 100644 --- a/todos_repository_core/lib/src/user_repository.dart +++ b/todos_repository_core/lib/src/user_repository.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'user_entity.dart'; diff --git a/todos_repository_core/lib/todos_repository_core.dart b/todos_repository_core/lib/todos_repository_core.dart index 2fe5da25..466e9bc1 100644 --- a/todos_repository_core/lib/todos_repository_core.dart +++ b/todos_repository_core/lib/todos_repository_core.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - library todos_repository; export 'src/reactive_repository.dart'; diff --git a/todos_repository_core/pubspec.yaml b/todos_repository_core/pubspec.yaml index 0c906d71..72d3a8cb 100644 --- a/todos_repository_core/pubspec.yaml +++ b/todos_repository_core/pubspec.yaml @@ -2,7 +2,7 @@ name: todos_repository_core description: An app-agnostic data source that can be used by all implementations environment: - sdk: '>=2.0.0 <3.0.0' + sdk: '>=3.0.0 <4.0.0' dependencies: meta: diff --git a/todos_repository_local_storage/lib/src/file_storage.dart b/todos_repository_local_storage/lib/src/file_storage.dart index f49ff4ef..0e010a87 100644 --- a/todos_repository_local_storage/lib/src/file_storage.dart +++ b/todos_repository_local_storage/lib/src/file_storage.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/todos_repository_local_storage/lib/src/key_value_storage.dart b/todos_repository_local_storage/lib/src/key_value_storage.dart index e43ea6ee..ad3d4832 100644 --- a/todos_repository_local_storage/lib/src/key_value_storage.dart +++ b/todos_repository_local_storage/lib/src/key_value_storage.dart @@ -1,10 +1,6 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:convert'; -import 'package:key_value_store/key_value_store.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; /// Loads and saves a List of Todos using a provided KeyValueStore, which works @@ -16,23 +12,29 @@ import 'package:todos_repository_core/todos_repository_core.dart'; /// LocalStorageRepository. class KeyValueStorage implements TodosRepository { final String key; - final KeyValueStore store; + final SharedPreferences sharedPreferences; final JsonCodec codec; - const KeyValueStorage(this.key, this.store, [this.codec = json]); + const KeyValueStorage(this.key, this.sharedPreferences, [this.codec = json]); @override Future> loadTodos() async { + final todos = sharedPreferences.getString(key); + + if (todos == null) { + throw Exception('No todos found for key: $key'); + } + return codec - .decode(store.getString(key))['todos'] - .cast>() + .decode(todos)['todos'] + .cast>() .map(TodoEntity.fromJson) .toList(growable: false); } @override Future saveTodos(List todos) { - return store.setString( + return sharedPreferences.setString( key, codec.encode({ 'todos': todos.map((todo) => todo.toJson()).toList(), diff --git a/todos_repository_local_storage/lib/src/reactive_repository.dart b/todos_repository_local_storage/lib/src/reactive_repository.dart index 2e0e4502..dd445161 100644 --- a/todos_repository_local_storage/lib/src/reactive_repository.dart +++ b/todos_repository_local_storage/lib/src/reactive_repository.dart @@ -1,11 +1,5 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; import 'dart:core'; -import 'package:meta/meta.dart'; import 'package:rxdart/subjects.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -17,8 +11,8 @@ class ReactiveLocalStorageRepository implements ReactiveTodosRepository { bool _loaded = false; ReactiveLocalStorageRepository({ - @required TodosRepository repository, - List seedValue, + required TodosRepository repository, + List? seedValue, }) : _repository = repository, _subject = seedValue != null ? BehaviorSubject>.seeded(seedValue) @@ -56,9 +50,10 @@ class ReactiveLocalStorageRepository implements ReactiveTodosRepository { _loaded = true; _repository.loadTodos().then((entities) { - _subject.add(List.unmodifiable( - [if (_subject.value != null) ..._subject.value, ...entities], - )); + _subject.add(List.unmodifiable([ + if (_subject.hasValue) ..._subject.value, + ...entities, + ])); }); } diff --git a/todos_repository_local_storage/lib/src/repository.dart b/todos_repository_local_storage/lib/src/repository.dart index eb5b52b8..b009e277 100644 --- a/todos_repository_local_storage/lib/src/repository.dart +++ b/todos_repository_local_storage/lib/src/repository.dart @@ -1,12 +1,7 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; import 'dart:core'; -import 'package:meta/meta.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; + import 'web_client.dart'; /// A class that glues together our local file storage and web client. It has a @@ -16,7 +11,7 @@ class LocalStorageRepository implements TodosRepository { final TodosRepository webClient; const LocalStorageRepository({ - @required this.localStorage, + required this.localStorage, this.webClient = const WebClient(), }); diff --git a/todos_repository_local_storage/lib/src/web_client.dart b/todos_repository_local_storage/lib/src/web_client.dart index 45138691..f4b1314c 100644 --- a/todos_repository_local_storage/lib/src/web_client.dart +++ b/todos_repository_local_storage/lib/src/web_client.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:todos_repository_core/todos_repository_core.dart'; diff --git a/todos_repository_local_storage/lib/todos_repository_local_storage.dart b/todos_repository_local_storage/lib/todos_repository_local_storage.dart index 21fdf1c6..f404dc4a 100644 --- a/todos_repository_local_storage/lib/todos_repository_local_storage.dart +++ b/todos_repository_local_storage/lib/todos_repository_local_storage.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - library todos_repository_simple; export 'src/file_storage.dart'; diff --git a/todos_repository_local_storage/pubspec.yaml b/todos_repository_local_storage/pubspec.yaml index 0587370d..6bb8c3f7 100644 --- a/todos_repository_local_storage/pubspec.yaml +++ b/todos_repository_local_storage/pubspec.yaml @@ -2,18 +2,19 @@ name: todos_repository_local_storage description: An app-agnostic data source that can be used by all implementations environment: - sdk: '>=2.2.2 <3.0.0' + sdk: '>=3.0.0 <4.0.0' dependencies: flutter: sdk: flutter todos_repository_core: path: ../todos_repository_core - rxdart: ^0.23.1 - key_value_store: + rxdart: + shared_preferences: dev_dependencies: test: flutter_test: sdk: flutter mockito: + build_runner: diff --git a/todos_repository_local_storage/test/file_storage_test.dart b/todos_repository_local_storage/test/file_storage_test.dart index e45a8897..2e8d81f9 100644 --- a/todos_repository_local_storage/test/file_storage_test.dart +++ b/todos_repository_local_storage/test/file_storage_test.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:io'; import 'package:test/test.dart'; diff --git a/todos_repository_local_storage/test/key_value_storage_test.dart b/todos_repository_local_storage/test/key_value_storage_test.dart index c59ff825..97ab6400 100644 --- a/todos_repository_local_storage/test/key_value_storage_test.dart +++ b/todos_repository_local_storage/test/key_value_storage_test.dart @@ -1,31 +1,33 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:key_value_store/key_value_store.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:test/test.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; -class MockKeyValueStore extends Mock implements KeyValueStore {} +import 'key_value_storage_test.mocks.dart'; +@GenerateNiceMocks([MockSpec()]) void main() { group('KeyValueStorage', () { - final store = MockKeyValueStore(); final todos = [TodoEntity('Task', '1', 'Hallo', true)]; final todosJson = '{"todos":[{"complete":true,"task":"Task","note":"Hallo","id":"1"}]}'; - final storage = KeyValueStorage('T', store); test('Should persist TodoEntities to the store', () async { + final prefs = MockSharedPreferences(); + final storage = KeyValueStorage('T', prefs); + await storage.saveTodos(todos); - verify(store.setString('T', todosJson)); + verify(prefs.setString('T', todosJson)); }); test('Should load TodoEntities from disk', () async { - when(store.getString('T')).thenReturn(todosJson); + final prefs = MockSharedPreferences(); + final storage = KeyValueStorage('T', prefs); + + when(prefs.getString('T')).thenReturn(todosJson); expect(await storage.loadTodos(), todos); }); diff --git a/todos_repository_local_storage/test/key_value_storage_test.mocks.dart b/todos_repository_local_storage/test/key_value_storage_test.mocks.dart new file mode 100644 index 00000000..f6af9524 --- /dev/null +++ b/todos_repository_local_storage/test/key_value_storage_test.mocks.dart @@ -0,0 +1,227 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in todos_repository_local_storage/test/key_value_storage_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:shared_preferences/src/shared_preferences_legacy.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +/// A class which mocks [SharedPreferences]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockSharedPreferences extends _i1.Mock implements _i2.SharedPreferences { + @override + Set getKeys() => (super.noSuchMethod( + Invocation.method( + #getKeys, + [], + ), + returnValue: {}, + returnValueForMissingStub: {}, + ) as Set); + + @override + Object? get(String? key) => (super.noSuchMethod( + Invocation.method( + #get, + [key], + ), + returnValueForMissingStub: null, + ) as Object?); + + @override + bool? getBool(String? key) => (super.noSuchMethod( + Invocation.method( + #getBool, + [key], + ), + returnValueForMissingStub: null, + ) as bool?); + + @override + int? getInt(String? key) => (super.noSuchMethod( + Invocation.method( + #getInt, + [key], + ), + returnValueForMissingStub: null, + ) as int?); + + @override + double? getDouble(String? key) => (super.noSuchMethod( + Invocation.method( + #getDouble, + [key], + ), + returnValueForMissingStub: null, + ) as double?); + + @override + String? getString(String? key) => (super.noSuchMethod( + Invocation.method( + #getString, + [key], + ), + returnValueForMissingStub: null, + ) as String?); + + @override + bool containsKey(String? key) => (super.noSuchMethod( + Invocation.method( + #containsKey, + [key], + ), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); + + @override + List? getStringList(String? key) => (super.noSuchMethod( + Invocation.method( + #getStringList, + [key], + ), + returnValueForMissingStub: null, + ) as List?); + + @override + _i3.Future setBool( + String? key, + bool? value, + ) => + (super.noSuchMethod( + Invocation.method( + #setBool, + [ + key, + value, + ], + ), + returnValue: _i3.Future.value(false), + returnValueForMissingStub: _i3.Future.value(false), + ) as _i3.Future); + + @override + _i3.Future setInt( + String? key, + int? value, + ) => + (super.noSuchMethod( + Invocation.method( + #setInt, + [ + key, + value, + ], + ), + returnValue: _i3.Future.value(false), + returnValueForMissingStub: _i3.Future.value(false), + ) as _i3.Future); + + @override + _i3.Future setDouble( + String? key, + double? value, + ) => + (super.noSuchMethod( + Invocation.method( + #setDouble, + [ + key, + value, + ], + ), + returnValue: _i3.Future.value(false), + returnValueForMissingStub: _i3.Future.value(false), + ) as _i3.Future); + + @override + _i3.Future setString( + String? key, + String? value, + ) => + (super.noSuchMethod( + Invocation.method( + #setString, + [ + key, + value, + ], + ), + returnValue: _i3.Future.value(false), + returnValueForMissingStub: _i3.Future.value(false), + ) as _i3.Future); + + @override + _i3.Future setStringList( + String? key, + List? value, + ) => + (super.noSuchMethod( + Invocation.method( + #setStringList, + [ + key, + value, + ], + ), + returnValue: _i3.Future.value(false), + returnValueForMissingStub: _i3.Future.value(false), + ) as _i3.Future); + + @override + _i3.Future remove(String? key) => (super.noSuchMethod( + Invocation.method( + #remove, + [key], + ), + returnValue: _i3.Future.value(false), + returnValueForMissingStub: _i3.Future.value(false), + ) as _i3.Future); + + @override + _i3.Future commit() => (super.noSuchMethod( + Invocation.method( + #commit, + [], + ), + returnValue: _i3.Future.value(false), + returnValueForMissingStub: _i3.Future.value(false), + ) as _i3.Future); + + @override + _i3.Future clear() => (super.noSuchMethod( + Invocation.method( + #clear, + [], + ), + returnValue: _i3.Future.value(false), + returnValueForMissingStub: _i3.Future.value(false), + ) as _i3.Future); + + @override + _i3.Future reload() => (super.noSuchMethod( + Invocation.method( + #reload, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); +} diff --git a/todos_repository_local_storage/test/reactive_repository_test.dart b/todos_repository_local_storage/test/reactive_repository_test.dart index 74453787..056ec214 100644 --- a/todos_repository_local_storage/test/reactive_repository_test.dart +++ b/todos_repository_local_storage/test/reactive_repository_test.dart @@ -1,16 +1,14 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; -class MockTodosRepository extends Mock implements TodosRepository {} +import 'reactive_repository_test.mocks.dart'; +@GenerateNiceMocks([MockSpec()]) void main() { group('ReactiveTodosRepository', () { List createTodos([String task = 'Task']) { @@ -62,11 +60,10 @@ void main() { when(repository.loadTodos()) .thenAnswer((_) => Future.value([])); - when(repository.saveTodos(todos)).thenAnswer((_) => Future.value()); await reactiveRepository.addNewTodo(todos.first); - verify(repository.saveTodos(any)); + verify(repository.saveTodos([todos.first])); expect(reactiveRepository.todos(), emits([todos.first])); }); diff --git a/todos_repository_local_storage/test/reactive_repository_test.mocks.dart b/todos_repository_local_storage/test/reactive_repository_test.mocks.dart new file mode 100644 index 00000000..9492a4e4 --- /dev/null +++ b/todos_repository_local_storage/test/reactive_repository_test.mocks.dart @@ -0,0 +1,51 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in todos_repository_local_storage/test/reactive_repository_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:todos_repository_core/src/todo_entity.dart' as _i4; +import 'package:todos_repository_core/src/todos_repository.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +/// A class which mocks [TodosRepository]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTodosRepository extends _i1.Mock implements _i2.TodosRepository { + @override + _i3.Future> loadTodos() => (super.noSuchMethod( + Invocation.method( + #loadTodos, + [], + ), + returnValue: _i3.Future>.value(<_i4.TodoEntity>[]), + returnValueForMissingStub: + _i3.Future>.value(<_i4.TodoEntity>[]), + ) as _i3.Future>); + + @override + _i3.Future saveTodos(List<_i4.TodoEntity>? todos) => + (super.noSuchMethod( + Invocation.method( + #saveTodos, + [todos], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); +} diff --git a/todos_repository_local_storage/test/repository_test.dart b/todos_repository_local_storage/test/repository_test.dart index 5774ce6f..c44d1028 100644 --- a/todos_repository_local_storage/test/repository_test.dart +++ b/todos_repository_local_storage/test/repository_test.dart @@ -1,21 +1,18 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'dart:io'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; -/// We create two Mocks for our Web Client and File Storage. We will use these -/// mock classes to verify the behavior of the TodosRepository. -class MockFileStorage extends Mock implements FileStorage {} - -class MockWebClient extends Mock implements WebClient {} +import 'repository_test.mocks.dart'; +@GenerateNiceMocks([ + MockSpec(), + MockSpec(), +]) void main() { group('TodosRepository', () { List createTodos() { diff --git a/todos_repository_local_storage/test/repository_test.mocks.dart b/todos_repository_local_storage/test/repository_test.mocks.dart new file mode 100644 index 00000000..ebf0cdbe --- /dev/null +++ b/todos_repository_local_storage/test/repository_test.mocks.dart @@ -0,0 +1,198 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in todos_repository_local_storage/test/repository_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i5; +import 'dart:io' as _i2; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i4; +import 'package:todos_repository_core/todos_repository_core.dart' as _i6; +import 'package:todos_repository_local_storage/src/file_storage.dart' as _i3; +import 'package:todos_repository_local_storage/src/web_client.dart' as _i7; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeDirectory_0 extends _i1.SmartFake implements _i2.Directory { + _FakeDirectory_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeFile_1 extends _i1.SmartFake implements _i2.File { + _FakeFile_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeFileSystemEntity_2 extends _i1.SmartFake + implements _i2.FileSystemEntity { + _FakeFileSystemEntity_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeDuration_3 extends _i1.SmartFake implements Duration { + _FakeDuration_3( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [FileStorage]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockFileStorage extends _i1.Mock implements _i3.FileStorage { + @override + String get tag => (super.noSuchMethod( + Invocation.getter(#tag), + returnValue: _i4.dummyValue( + this, + Invocation.getter(#tag), + ), + returnValueForMissingStub: _i4.dummyValue( + this, + Invocation.getter(#tag), + ), + ) as String); + + @override + _i5.Future<_i2.Directory> Function() get getDirectory => (super.noSuchMethod( + Invocation.getter(#getDirectory), + returnValue: () => _i5.Future<_i2.Directory>.value(_FakeDirectory_0( + this, + Invocation.getter(#getDirectory), + )), + returnValueForMissingStub: () => + _i5.Future<_i2.Directory>.value(_FakeDirectory_0( + this, + Invocation.getter(#getDirectory), + )), + ) as _i5.Future<_i2.Directory> Function()); + + @override + _i5.Future> loadTodos() => (super.noSuchMethod( + Invocation.method( + #loadTodos, + [], + ), + returnValue: _i5.Future>.value(<_i6.TodoEntity>[]), + returnValueForMissingStub: + _i5.Future>.value(<_i6.TodoEntity>[]), + ) as _i5.Future>); + + @override + _i5.Future<_i2.File> saveTodos(List<_i6.TodoEntity>? todos) => + (super.noSuchMethod( + Invocation.method( + #saveTodos, + [todos], + ), + returnValue: _i5.Future<_i2.File>.value(_FakeFile_1( + this, + Invocation.method( + #saveTodos, + [todos], + ), + )), + returnValueForMissingStub: _i5.Future<_i2.File>.value(_FakeFile_1( + this, + Invocation.method( + #saveTodos, + [todos], + ), + )), + ) as _i5.Future<_i2.File>); + + @override + _i5.Future<_i2.FileSystemEntity> clean() => (super.noSuchMethod( + Invocation.method( + #clean, + [], + ), + returnValue: + _i5.Future<_i2.FileSystemEntity>.value(_FakeFileSystemEntity_2( + this, + Invocation.method( + #clean, + [], + ), + )), + returnValueForMissingStub: + _i5.Future<_i2.FileSystemEntity>.value(_FakeFileSystemEntity_2( + this, + Invocation.method( + #clean, + [], + ), + )), + ) as _i5.Future<_i2.FileSystemEntity>); +} + +/// A class which mocks [WebClient]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockWebClient extends _i1.Mock implements _i7.WebClient { + @override + Duration get delay => (super.noSuchMethod( + Invocation.getter(#delay), + returnValue: _FakeDuration_3( + this, + Invocation.getter(#delay), + ), + returnValueForMissingStub: _FakeDuration_3( + this, + Invocation.getter(#delay), + ), + ) as Duration); + + @override + _i5.Future> loadTodos() => (super.noSuchMethod( + Invocation.method( + #loadTodos, + [], + ), + returnValue: _i5.Future>.value(<_i6.TodoEntity>[]), + returnValueForMissingStub: + _i5.Future>.value(<_i6.TodoEntity>[]), + ) as _i5.Future>); + + @override + _i5.Future saveTodos(List<_i6.TodoEntity>? todos) => + (super.noSuchMethod( + Invocation.method( + #saveTodos, + [todos], + ), + returnValue: _i5.Future.value(false), + returnValueForMissingStub: _i5.Future.value(false), + ) as _i5.Future); +} diff --git a/vanilla/.gitignore b/vanilla/.gitignore index 2ddde2a5..e378fe70 100644 --- a/vanilla/.gitignore +++ b/vanilla/.gitignore @@ -5,9 +5,12 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ +migrate_working_dir/ # IntelliJ related *.iml @@ -18,56 +21,27 @@ # 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 # is commented out by default. -#.vscode/ +.vscode/ # Flutter/Dart/Pub related **/doc/api/ +**/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins -.packages +.flutter-plugins-dependencies .pub-cache/ .pub/ /build/ -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java +# Symbolication related +app.*.symbols -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* +# Obfuscation related +app.*.map.json -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +.fvm diff --git a/vanilla/.metadata b/vanilla/.metadata index 1b5cec02..05a8ab44 100644 --- a/vanilla/.metadata +++ b/vanilla/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: 27321ebbad34b0a3fafe99fac037102196d655ff - channel: stable + revision: "05db9689081f091050f01aed79f04dce0c750154" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: android + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: ios + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: linux + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: macos + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: web + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + - platform: windows + create_revision: 05db9689081f091050f01aed79f04dce0c750154 + base_revision: 05db9689081f091050f01aed79f04dce0c750154 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/vanilla/analysis_options.yaml b/vanilla/analysis_options.yaml new file mode 100644 index 00000000..134f2137 --- /dev/null +++ b/vanilla/analysis_options.yaml @@ -0,0 +1,34 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# 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 +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + # The lint rules applied to this project can be customized in the + # 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 + # and their documentation is published at https://dart.dev/lints. + # + # 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 + # 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 + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/vanilla/android/.gitignore b/vanilla/android/.gitignore index bc2100d8..be3943c9 100644 --- a/vanilla/android/.gitignore +++ b/vanilla/android/.gitignore @@ -5,3 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/vanilla/android/app/build.gradle b/vanilla/android/app/build.gradle deleted file mode 100644 index 7489a6f9..00000000 --- a/vanilla/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.vanilla" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/vanilla/android/app/build.gradle.kts b/vanilla/android/app/build.gradle.kts new file mode 100644 index 00000000..714aef16 --- /dev/null +++ b/vanilla/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.vanilla" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.vanilla" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/vanilla/android/app/src/debug/AndroidManifest.xml b/vanilla/android/app/src/debug/AndroidManifest.xml index d1bf7acd..399f6981 100644 --- a/vanilla/android/app/src/debug/AndroidManifest.xml +++ b/vanilla/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/vanilla/android/app/src/main/AndroidManifest.xml b/vanilla/android/app/src/main/AndroidManifest.xml index 7ee3bec6..732b20b0 100644 --- a/vanilla/android/app/src/main/AndroidManifest.xml +++ b/vanilla/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,25 @@ - - + + + @@ -27,4 +31,15 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + diff --git a/vanilla/android/app/src/main/kotlin/com/example/vanilla/MainActivity.kt b/vanilla/android/app/src/main/kotlin/com/example/vanilla/MainActivity.kt index 54d143cf..bd7af163 100644 --- a/vanilla/android/app/src/main/kotlin/com/example/vanilla/MainActivity.kt +++ b/vanilla/android/app/src/main/kotlin/com/example/vanilla/MainActivity.kt @@ -1,12 +1,5 @@ package com.example.vanilla -import androidx.annotation.NonNull; import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} +class MainActivity : FlutterActivity() diff --git a/vanilla/android/app/src/main/res/drawable-v21/launch_background.xml b/vanilla/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/vanilla/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/vanilla/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/vanilla/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index a3f285f9..db77bb4b 100644 Binary files a/vanilla/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/vanilla/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/vanilla/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/vanilla/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 5e6f3ac6..17987b79 100644 Binary files a/vanilla/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/vanilla/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/vanilla/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/vanilla/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 144d60be..09d43914 100644 Binary files a/vanilla/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/vanilla/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/vanilla/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/vanilla/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index deafae2d..d5f1c8d3 100644 Binary files a/vanilla/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/vanilla/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/vanilla/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/vanilla/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index d5614ac8..4d6372ee 100644 Binary files a/vanilla/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/vanilla/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/vanilla/android/app/src/main/res/values-night/styles.xml b/vanilla/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/vanilla/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/vanilla/android/app/src/main/res/values/styles.xml b/vanilla/android/app/src/main/res/values/styles.xml index 00fa4417..cb1ef880 100644 --- a/vanilla/android/app/src/main/res/values/styles.xml +++ b/vanilla/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ - + + diff --git a/vanilla/android/app/src/profile/AndroidManifest.xml b/vanilla/android/app/src/profile/AndroidManifest.xml index d1bf7acd..399f6981 100644 --- a/vanilla/android/app/src/profile/AndroidManifest.xml +++ b/vanilla/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/vanilla/android/build.gradle b/vanilla/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/vanilla/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/vanilla/android/build.gradle.kts b/vanilla/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/vanilla/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/vanilla/android/gradle.properties b/vanilla/android/gradle.properties index 38c8d454..f018a618 100644 --- a/vanilla/android/gradle.properties +++ b/vanilla/android/gradle.properties @@ -1,4 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/vanilla/android/gradle/wrapper/gradle-wrapper.properties b/vanilla/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..ac3b4792 100644 --- a/vanilla/android/gradle/wrapper/gradle-wrapper.properties +++ b/vanilla/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/vanilla/android/settings.gradle b/vanilla/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/vanilla/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/vanilla/android/settings.gradle.kts b/vanilla/android/settings.gradle.kts new file mode 100644 index 00000000..fb605bc8 --- /dev/null +++ b/vanilla/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/vanilla/integration_test/app_test.dart b/vanilla/integration_test/app_test.dart new file mode 100644 index 00000000..75cd7bb3 --- /dev/null +++ b/vanilla/integration_test/app_test.dart @@ -0,0 +1,19 @@ +import 'package:integration_tests/integration_tests.dart' as integration_tests; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; +import 'package:vanilla/app.dart'; + +void main() { + integration_tests.run( + appBuilder: () async { + return VanillaApp( + repository: LocalStorageRepository( + localStorage: KeyValueStorage( + 'vanilla_test_${DateTime.now().toIso8601String()}', + await SharedPreferences.getInstance(), + ), + ), + ); + }, + ); +} diff --git a/vanilla/ios/.gitignore b/vanilla/ios/.gitignore index e96ef602..7a7f9873 100644 --- a/vanilla/ios/.gitignore +++ b/vanilla/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/vanilla/ios/Flutter/AppFrameworkInfo.plist b/vanilla/ios/Flutter/AppFrameworkInfo.plist index 6b4c0f78..1dc6cf76 100644 --- a/vanilla/ios/Flutter/AppFrameworkInfo.plist +++ b/vanilla/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 13.0 diff --git a/vanilla/ios/Flutter/Debug.xcconfig b/vanilla/ios/Flutter/Debug.xcconfig index e8efba11..ec97fc6f 100644 --- a/vanilla/ios/Flutter/Debug.xcconfig +++ b/vanilla/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/vanilla/ios/Flutter/Release.xcconfig b/vanilla/ios/Flutter/Release.xcconfig index 399e9340..c4855bfe 100644 --- a/vanilla/ios/Flutter/Release.xcconfig +++ b/vanilla/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/vanilla/ios/Podfile b/vanilla/ios/Podfile index b30a428b..620e46eb 100644 --- a/vanilla/ios/Podfile +++ b/vanilla/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -10,81 +10,34 @@ project 'Runner', { 'Release' => :release, } -def parse_KV_file(file, separator='=') - file_abs_path = File.expand_path(file) - if !File.exists? file_abs_path - return []; +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end - generated_key_values = {} - skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) do |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - generated_key_values[podname] = podpath - else - puts "Invalid plugin specification: #{line}" - end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches end - generated_key_values + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end -target 'Runner' do - use_frameworks! - use_modular_headers! - - # Flutter Pod - - copied_flutter_dir = File.join(__dir__, 'Flutter') - copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') - copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') - unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) - # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. - # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. - # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. - - generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') - unless File.exist?(generated_xcode_build_settings_path) - raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) - cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - unless File.exist?(copied_framework_path) - FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) - end - unless File.exist?(copied_podspec_path) - FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) - end - end - - # Keep pod path relative so it can be checked into Podfile.lock. - pod 'Flutter', :path => 'Flutter' +flutter_ios_podfile_setup - # Plugin Pods +target 'Runner' do + use_frameworks! - # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock - # referring to absolute paths on developers' machines. - system('rm -rf .symlinks') - system('mkdir -p .symlinks/plugins') - plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.each do |name, path| - symlink = File.join('.symlinks', 'plugins', name) - File.symlink(path, symlink) - pod name, :path => File.join(symlink, 'ios') + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths end end -# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. -install! 'cocoapods', :disable_input_output_paths => true - post_install do |installer| installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['ENABLE_BITCODE'] = 'NO' - end + flutter_additional_ios_build_settings(target) end end diff --git a/vanilla/ios/Runner.xcodeproj/project.pbxproj b/vanilla/ios/Runner.xcodeproj/project.pbxproj index f8757c55..50f8c90f 100644 --- a/vanilla/ios/Runner.xcodeproj/project.pbxproj +++ b/vanilla/ios/Runner.xcodeproj/project.pbxproj @@ -3,22 +3,29 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -26,8 +33,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -37,14 +42,14 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -57,20 +62,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -84,6 +93,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -91,6 +101,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -102,7 +113,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -111,16 +121,26 @@ path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; @@ -147,9 +167,14 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -157,7 +182,7 @@ }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -170,11 +195,19 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -191,20 +224,23 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -220,6 +256,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -231,6 +275,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -253,9 +305,9 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -285,6 +337,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -293,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -309,16 +362,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.example.vanilla; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -328,11 +377,58 @@ }; name = Profile; }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.vanilla.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.vanilla.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.vanilla.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -362,6 +458,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -376,7 +473,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -386,9 +483,9 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -418,6 +515,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -426,11 +524,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -443,16 +542,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.example.vanilla; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -470,16 +565,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 8W92H589V9; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.example.vanilla; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -492,6 +583,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/vanilla/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/vanilla/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/vanilla/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/vanilla/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/vanilla/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/vanilla/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/vanilla/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/vanilla/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/vanilla/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/vanilla/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/vanilla/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/vanilla/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..e3773d42 100644 --- a/vanilla/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/vanilla/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + + + + + @@ -61,8 +73,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - + + + + IDEDidComputeMac32BitWarning + + + diff --git a/vanilla/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/vanilla/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/vanilla/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/vanilla/ios/Runner/AppDelegate.swift b/vanilla/ios/Runner/AppDelegate.swift index 70693e4a..62666446 100644 --- a/vanilla/ios/Runner/AppDelegate.swift +++ b/vanilla/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ -import UIKit import Flutter +import UIKit -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d22f10b2..d36b1fab 100644 --- a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -107,6 +107,12 @@ "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" } ], "info" : { diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 980e5ad6..7353c41e 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index fd870289..797d452e 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 75e84cd1..6ed2d933 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 03ab8a84..4cd7b009 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index a03431cb..fe730945 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index f47613ee..321773cd 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 7f2230a9..797d452e 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 42315c6d..502f463a 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index f9882cc0..0ec30343 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index 8c552e23..00000000 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 45537513..0ec30343 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 6360ea17..e9f5fea2 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 152d5e12..84ac32ae 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 310b0b8f..8953cba0 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index 40ac4ea7..00000000 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png deleted file mode 100644 index dfc408df..00000000 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@1x.png and /dev/null differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 092b7bfe..0467bf12 100644 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png b/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png deleted file mode 100644 index 521c3e2a..00000000 Binary files a/vanilla/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@3x.png and /dev/null differ diff --git a/vanilla/ios/Runner/Info.plist b/vanilla/ios/Runner/Info.plist index bd94c30a..59cf3a65 100644 --- a/vanilla/ios/Runner/Info.plist +++ b/vanilla/ios/Runner/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Vanilla CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -39,7 +41,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/vanilla/ios/Runner/Runner-Bridging-Header.h b/vanilla/ios/Runner/Runner-Bridging-Header.h index 7335fdf9..308a2a56 100644 --- a/vanilla/ios/Runner/Runner-Bridging-Header.h +++ b/vanilla/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file +#import "GeneratedPluginRegistrant.h" diff --git a/vanilla/ios/RunnerTests/RunnerTests.swift b/vanilla/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/vanilla/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/vanilla/lib/app.dart b/vanilla/lib/app.dart index e544ba8f..03407eb7 100644 --- a/vanilla/lib/app.dart +++ b/vanilla/lib/app.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -11,10 +6,11 @@ import 'package:vanilla/models.dart'; import 'package:vanilla/screens/add_edit_screen.dart'; import 'package:vanilla/screens/home_screen.dart'; +@immutable class VanillaApp extends StatefulWidget { final TodosRepository repository; - VanillaApp({@required this.repository}); + const VanillaApp({super.key, required this.repository}); @override State createState() { @@ -29,24 +25,28 @@ class VanillaAppState extends State { void initState() { super.initState(); - widget.repository.loadTodos().then((loadedTodos) { - setState(() { - appState = AppState( - todos: loadedTodos.map(Todo.fromEntity).toList(), - ); - }); - }).catchError((err) { - setState(() { - appState.isLoading = false; - }); - }); + widget.repository + .loadTodos() + .then((loadedTodos) { + setState(() { + appState = AppState( + todos: loadedTodos.map(Todo.fromEntity).toList(), + ); + }); + }) + .catchError((err) { + setState(() { + appState.isLoading = false; + }); + }); } @override Widget build(BuildContext context) { return MaterialApp( onGenerateTitle: (context) => VanillaLocalizations.of(context).appTitle, - theme: ArchSampleTheme.theme, + theme: ArchSampleTheme.lightTheme, + darkTheme: ArchSampleTheme.darkTheme, localizationsDelegates: [ ArchSampleLocalizationsDelegate(), VanillaLocalizationsDelegate(), @@ -99,10 +99,10 @@ class VanillaAppState extends State { void updateTodo( Todo todo, { - bool complete, - String id, - String note, - String task, + bool? complete, + String? id, + String? note, + String? task, }) { setState(() { todo.complete = complete ?? todo.complete; diff --git a/vanilla/lib/localization.dart b/vanilla/lib/localization.dart index 01a21469..edbb413c 100644 --- a/vanilla/lib/localization.dart +++ b/vanilla/lib/localization.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'dart:async'; import 'package:flutter/material.dart'; @@ -9,7 +5,9 @@ import 'package:flutter/material.dart'; class VanillaLocalizations { static VanillaLocalizations of(BuildContext context) { return Localizations.of( - context, VanillaLocalizations); + context, + VanillaLocalizations, + )!; } String get appTitle => 'Vanilla Example'; diff --git a/vanilla/lib/main.dart b/vanilla/lib/main.dart index 48a3702f..58407c6a 100644 --- a/vanilla/lib/main.dart +++ b/vanilla/lib/main.dart @@ -1,9 +1,4 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; -import 'package:key_value_store_flutter/key_value_store_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; import 'package:vanilla/app.dart'; @@ -16,7 +11,7 @@ Future main() async { repository: LocalStorageRepository( localStorage: KeyValueStorage( 'vanilla', - FlutterKeyValueStore(await SharedPreferences.getInstance()), + await SharedPreferences.getInstance(), ), ), ), diff --git a/vanilla/lib/main_web.dart b/vanilla/lib/main_web.dart deleted file mode 100644 index 4d1b687e..00000000 --- a/vanilla/lib/main_web.dart +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:html'; - -import 'package:flutter/material.dart'; -import 'package:key_value_store_web/key_value_store_web.dart'; -import 'package:todos_repository_local_storage/todos_repository_local_storage.dart'; -import 'package:vanilla/app.dart'; - -Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - - runApp( - VanillaApp( - repository: LocalStorageRepository( - localStorage: KeyValueStorage( - 'vanilla', - WebKeyValueStore(window.localStorage), - ), - ), - ), - ); -} diff --git a/vanilla/lib/models.dart b/vanilla/lib/models.dart index 50f610f6..3d616754 100644 --- a/vanilla/lib/models.dart +++ b/vanilla/lib/models.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:todos_app_core/todos_app_core.dart'; import 'package:todos_repository_core/todos_repository_core.dart'; @@ -9,10 +5,7 @@ class AppState { bool isLoading; List todos; - AppState({ - this.isLoading = false, - this.todos = const [], - }); + AppState({this.isLoading = false, this.todos = const []}); factory AppState.loading() => AppState(isLoading: true); @@ -26,7 +19,6 @@ class AppState { case VisibilityFilter.completed: return todo.complete; case VisibilityFilter.all: - default: return true; } }).toList(); @@ -57,7 +49,9 @@ class AppState { void toggleAll() { final allCompleted = allComplete; - todos.forEach((todo) => todo.complete = !allCompleted); + for (final todo in todos) { + todo.complete = !allCompleted; + } } @override @@ -76,8 +70,8 @@ class Todo { String note; String task; - Todo(this.task, {this.complete = false, this.note = '', String id}) - : id = id ?? Uuid().generateV4(); + Todo(this.task, {this.complete = false, this.note = '', String? id}) + : id = id ?? Uuid().generateV4(); @override int get hashCode => @@ -105,9 +99,9 @@ class Todo { static Todo fromEntity(TodoEntity entity) { return Todo( entity.task, - complete: entity.complete ?? false, + complete: entity.complete, note: entity.note, - id: entity.id ?? Uuid().generateV4(), + id: entity.id, ); } } diff --git a/vanilla/lib/screens/add_edit_screen.dart b/vanilla/lib/screens/add_edit_screen.dart index 8c9e93f7..e4e8bfd0 100644 --- a/vanilla/lib/screens/add_edit_screen.dart +++ b/vanilla/lib/screens/add_edit_screen.dart @@ -1,109 +1,101 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'package:vanilla/models.dart'; import 'package:vanilla/widgets/typedefs.dart'; class AddEditScreen extends StatefulWidget { - final Todo todo; + final Todo? todo; final TodoAdder addTodo; final TodoUpdater updateTodo; - AddEditScreen({ - Key key, - @required this.addTodo, - @required this.updateTodo, + const AddEditScreen({ + super.key = ArchSampleKeys.addTodoScreen, + required this.addTodo, + required this.updateTodo, this.todo, - }) : super(key: key ?? ArchSampleKeys.addTodoScreen); + }); @override - _AddEditScreenState createState() => _AddEditScreenState(); + State createState() => _AddEditScreenState(); } class _AddEditScreenState extends State { - static final GlobalKey formKey = GlobalKey(); + final GlobalKey _formKey = GlobalKey(); - String _task; - String _note; + String? _task; + String? _note; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(isEditing - ? ArchSampleLocalizations.of(context).editTodo - : ArchSampleLocalizations.of(context).addTodo), + title: Text( + isEditing + ? ArchSampleLocalizations.of(context).editTodo + : ArchSampleLocalizations.of(context).addTodo, + ), ), body: Padding( padding: EdgeInsets.all(16.0), child: Form( - key: formKey, - autovalidate: false, - onWillPop: () { - return Future(() => true); - }, + key: _formKey, + canPop: true, child: ListView( children: [ TextFormField( - initialValue: widget.todo != null ? widget.todo.task : '', + initialValue: widget.todo != null ? widget.todo!.task : '', key: ArchSampleKeys.taskField, autofocus: isEditing ? false : true, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.titleLarge, decoration: InputDecoration( - hintText: ArchSampleLocalizations.of(context).newTodoHint), - validator: (val) => val.trim().isEmpty + hintText: ArchSampleLocalizations.of(context).newTodoHint, + ), + validator: (val) => val?.trim().isEmpty ?? true ? ArchSampleLocalizations.of(context).emptyTodoError : null, onSaved: (value) => _task = value, ), TextFormField( - initialValue: widget.todo != null ? widget.todo.note : '', + initialValue: widget.todo != null ? widget.todo!.note : '', key: ArchSampleKeys.noteField, maxLines: 10, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.bodyMedium, decoration: InputDecoration( hintText: ArchSampleLocalizations.of(context).notesHint, ), onSaved: (value) => _note = value, - ) + ), ], ), ), ), floatingActionButton: FloatingActionButton( - key: isEditing - ? ArchSampleKeys.saveTodoFab - : ArchSampleKeys.saveNewTodo, - tooltip: isEditing - ? ArchSampleLocalizations.of(context).saveChanges - : ArchSampleLocalizations.of(context).addTodo, - child: Icon(isEditing ? Icons.check : Icons.add), - onPressed: () { - final form = formKey.currentState; - if (form.validate()) { - form.save(); + key: isEditing + ? ArchSampleKeys.saveTodoFab + : ArchSampleKeys.saveNewTodo, + tooltip: isEditing + ? ArchSampleLocalizations.of(context).saveChanges + : ArchSampleLocalizations.of(context).addTodo, + child: Icon(Icons.check), + onPressed: () { + final form = _formKey.currentState!; - final task = _task; - final note = _note; + if (form.validate()) { + form.save(); - if (isEditing) { - widget.updateTodo(widget.todo, task: task, note: note); - } else { - widget.addTodo(Todo( - task, - note: note, - )); - } + final task = _task!; + final note = _note!; - Navigator.pop(context); + if (isEditing) { + widget.updateTodo(widget.todo!, task: task, note: note); + } else { + widget.addTodo(Todo(task, note: note)); } - }), + + Navigator.pop(context); + } + }, + ), ); } diff --git a/vanilla/lib/screens/detail_screen.dart b/vanilla/lib/screens/detail_screen.dart index 0c3b0958..c96f1488 100644 --- a/vanilla/lib/screens/detail_screen.dart +++ b/vanilla/lib/screens/detail_screen.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'package:vanilla/models.dart'; @@ -15,12 +10,13 @@ class DetailScreen extends StatelessWidget { final TodoAdder addTodo; final TodoUpdater updateTodo; - DetailScreen({ - @required this.todo, - @required this.addTodo, - @required this.updateTodo, - @required this.onDelete, - }) : super(key: ArchSampleKeys.todoDetailsScreen); + const DetailScreen({ + super.key = ArchSampleKeys.todoDetailsScreen, + required this.todo, + required this.addTodo, + required this.updateTodo, + required this.onDelete, + }); @override Widget build(BuildContext context) { @@ -36,7 +32,7 @@ class DetailScreen extends StatelessWidget { onDelete(); Navigator.pop(context, todo); }, - ) + ), ], ), body: Padding( @@ -61,21 +57,18 @@ class DetailScreen extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.only( - top: 8.0, - bottom: 16.0, - ), + padding: EdgeInsets.only(top: 8.0, bottom: 16.0), child: Text( todo.task, key: ArchSampleKeys.detailsTodoItemTask, - style: Theme.of(context).textTheme.headline, + style: Theme.of(context).textTheme.headlineSmall, ), ), Text( todo.note, key: ArchSampleKeys.detailsTodoItemNote, - style: Theme.of(context).textTheme.subhead, - ) + style: Theme.of(context).textTheme.titleMedium, + ), ], ), ), @@ -86,10 +79,9 @@ class DetailScreen extends StatelessWidget { ), floatingActionButton: FloatingActionButton( tooltip: ArchSampleLocalizations.of(context).editTodo, - child: Icon(Icons.edit), key: ArchSampleKeys.editTodoFab, onPressed: () { - Navigator.of(context).push( + Navigator.of(context).push( MaterialPageRoute( builder: (context) { return AddEditScreen( @@ -102,6 +94,7 @@ class DetailScreen extends StatelessWidget { ), ); }, + child: Icon(Icons.edit), ), ); } diff --git a/vanilla/lib/screens/home_screen.dart b/vanilla/lib/screens/home_screen.dart index 43589afc..71ce7876 100644 --- a/vanilla/lib/screens/home_screen.dart +++ b/vanilla/lib/screens/home_screen.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'package:vanilla/localization.dart'; @@ -21,15 +16,15 @@ class HomeScreen extends StatefulWidget { final Function toggleAll; final Function clearCompleted; - HomeScreen({ - @required this.appState, - @required this.addTodo, - @required this.removeTodo, - @required this.updateTodo, - @required this.toggleAll, - @required this.clearCompleted, - Key key, - }) : super(key: ArchSampleKeys.homeScreen); + const HomeScreen({ + required this.appState, + required this.addTodo, + required this.removeTodo, + required this.updateTodo, + required this.toggleAll, + required this.clearCompleted, + super.key = ArchSampleKeys.homeScreen, + }); @override State createState() { @@ -74,7 +69,7 @@ class HomeScreenState extends State { widget.clearCompleted(); } }, - ) + ), ], ), body: activeTab == AppTab.todos @@ -94,8 +89,8 @@ class HomeScreenState extends State { onPressed: () { Navigator.pushNamed(context, ArchSampleRoutes.addTodo); }, - child: Icon(Icons.add), tooltip: ArchSampleLocalizations.of(context).addTodo, + child: Icon(Icons.add), ), bottomNavigationBar: BottomNavigationBar( key: ArchSampleKeys.tabs, @@ -111,11 +106,9 @@ class HomeScreenState extends State { ? ArchSampleKeys.statsTab : ArchSampleKeys.todoTab, ), - title: Text( - tab == AppTab.stats - ? ArchSampleLocalizations.of(context).stats - : ArchSampleLocalizations.of(context).todos, - ), + label: tab == AppTab.stats + ? ArchSampleLocalizations.of(context).stats + : ArchSampleLocalizations.of(context).todos, ); }).toList(), ), diff --git a/vanilla/lib/widgets/extra_actions_button.dart b/vanilla/lib/widgets/extra_actions_button.dart index bc2aff03..5c349708 100644 --- a/vanilla/lib/widgets/extra_actions_button.dart +++ b/vanilla/lib/widgets/extra_actions_button.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'package:vanilla/models.dart'; @@ -11,25 +7,26 @@ class ExtraActionsButton extends StatelessWidget { final bool allComplete; final bool hasCompletedTodos; - ExtraActionsButton({ - this.onSelected, + const ExtraActionsButton({ + required this.onSelected, this.allComplete = false, this.hasCompletedTodos = true, - Key key, - }) : super(key: key); + super.key = ArchSampleKeys.extraActionsButton, + }); @override Widget build(BuildContext context) { return PopupMenuButton( - key: ArchSampleKeys.extraActionsButton, onSelected: onSelected, itemBuilder: (BuildContext context) => >[ PopupMenuItem( key: ArchSampleKeys.toggleAll, value: ExtraAction.toggleAllComplete, - child: Text(allComplete - ? ArchSampleLocalizations.of(context).markAllIncomplete - : ArchSampleLocalizations.of(context).markAllComplete), + child: Text( + allComplete + ? ArchSampleLocalizations.of(context).markAllIncomplete + : ArchSampleLocalizations.of(context).markAllComplete, + ), ), PopupMenuItem( key: ArchSampleKeys.clearCompleted, diff --git a/vanilla/lib/widgets/filter_button.dart b/vanilla/lib/widgets/filter_button.dart index beff7085..81596bc5 100644 --- a/vanilla/lib/widgets/filter_button.dart +++ b/vanilla/lib/widgets/filter_button.dart @@ -1,7 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'package:vanilla/models.dart'; @@ -11,16 +7,19 @@ class FilterButton extends StatelessWidget { final VisibilityFilter activeFilter; final bool isActive; - FilterButton({this.onSelected, this.activeFilter, this.isActive, Key key}) - : super(key: key); + const FilterButton({ + required this.onSelected, + required this.activeFilter, + required this.isActive, + super.key = ArchSampleKeys.filterButton, + }); @override Widget build(BuildContext context) { - final defaultStyle = Theme.of(context).textTheme.body1; - final activeStyle = Theme.of(context) - .textTheme - .body1 - .copyWith(color: Theme.of(context).accentColor); + final defaultStyle = Theme.of(context).textTheme.bodyMedium!; + final activeStyle = defaultStyle.copyWith( + color: Theme.of(context).colorScheme.secondary, + ); final button = _Button( onSelected: onSelected, activeFilter: activeFilter, @@ -38,12 +37,11 @@ class FilterButton extends StatelessWidget { class _Button extends StatelessWidget { const _Button({ - Key key, - @required this.onSelected, - @required this.activeFilter, - @required this.activeStyle, - @required this.defaultStyle, - }) : super(key: key); + required this.onSelected, + required this.activeFilter, + required this.activeStyle, + required this.defaultStyle, + }); final PopupMenuItemSelected onSelected; final VisibilityFilter activeFilter; @@ -53,7 +51,6 @@ class _Button extends StatelessWidget { @override Widget build(BuildContext context) { return PopupMenuButton( - key: ArchSampleKeys.filterButton, tooltip: ArchSampleLocalizations.of(context).filterTodos, onSelected: onSelected, itemBuilder: (BuildContext context) => >[ diff --git a/vanilla/lib/widgets/stats_counter.dart b/vanilla/lib/widgets/stats_counter.dart index d058d2a5..d8d24682 100644 --- a/vanilla/lib/widgets/stats_counter.dart +++ b/vanilla/lib/widgets/stats_counter.dart @@ -1,9 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; @@ -11,8 +5,8 @@ class StatsCounter extends StatelessWidget { final int numActive; final int numCompleted; - StatsCounter({@required this.numActive, @required this.numCompleted}) - : super(key: ArchSampleKeys.statsCounter); + const StatsCounter({required this.numActive, required this.numCompleted}) + : super(key: ArchSampleKeys.statsCounter); @override Widget build(BuildContext context) { @@ -24,7 +18,7 @@ class StatsCounter extends StatelessWidget { padding: EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).completedTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -32,14 +26,14 @@ class StatsCounter extends StatelessWidget { child: Text( '$numCompleted', key: ArchSampleKeys.statsNumCompleted, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), Padding( padding: EdgeInsets.only(bottom: 8.0), child: Text( ArchSampleLocalizations.of(context).activeTodos, - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), ), Padding( @@ -47,9 +41,9 @@ class StatsCounter extends StatelessWidget { child: Text( '$numActive', key: ArchSampleKeys.statsNumActive, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), - ) + ), ], ), ); diff --git a/vanilla/lib/widgets/todo_item.dart b/vanilla/lib/widgets/todo_item.dart index 391bc3ff..8c821208 100644 --- a/vanilla/lib/widgets/todo_item.dart +++ b/vanilla/lib/widgets/todo_item.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'package:vanilla/models.dart'; @@ -10,16 +5,16 @@ import 'package:vanilla/models.dart'; class TodoItem extends StatelessWidget { final DismissDirectionCallback onDismissed; final GestureTapCallback onTap; - final ValueChanged onCheckboxChanged; + final ValueChanged onCheckboxChanged; final Todo todo; - TodoItem({ - Key key, - @required this.onDismissed, - @required this.onTap, - @required this.onCheckboxChanged, - @required this.todo, - }) : super(key: key); + const TodoItem({ + super.key, + required this.onDismissed, + required this.onTap, + required this.onCheckboxChanged, + required this.todo, + }); @override Widget build(BuildContext context) { @@ -36,14 +31,14 @@ class TodoItem extends StatelessWidget { title: Text( todo.task, key: ArchSampleKeys.todoItemTask(todo.id), - style: Theme.of(context).textTheme.title, + style: Theme.of(context).textTheme.titleLarge, ), subtitle: Text( todo.note, key: ArchSampleKeys.todoItemNote(todo.id), maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.subhead, + style: Theme.of(context).textTheme.titleMedium, ), ), ); diff --git a/vanilla/lib/widgets/todo_list.dart b/vanilla/lib/widgets/todo_list.dart index 2483f7fd..ae8451b8 100644 --- a/vanilla/lib/widgets/todo_list.dart +++ b/vanilla/lib/widgets/todo_list.dart @@ -1,8 +1,3 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:todos_app_core/todos_app_core.dart'; import 'package:vanilla/models.dart'; @@ -17,13 +12,14 @@ class TodoList extends StatelessWidget { final TodoRemover removeTodo; final TodoUpdater updateTodo; - TodoList({ - @required this.filteredTodos, - @required this.loading, - @required this.addTodo, - @required this.removeTodo, - @required this.updateTodo, - }) : super(key: ArchSampleKeys.todoList); + const TodoList({ + required this.filteredTodos, + required this.loading, + required this.addTodo, + required this.removeTodo, + required this.updateTodo, + super.key, + }); @override Widget build(BuildContext context) { @@ -31,8 +27,9 @@ class TodoList extends StatelessWidget { child: loading ? Center( child: CircularProgressIndicator( - key: ArchSampleKeys.todosLoading, - )) + key: ArchSampleKeys.todosLoading, + ), + ) : ListView.builder( key: ArchSampleKeys.todoList, itemCount: filteredTodos.length, @@ -45,7 +42,7 @@ class TodoList extends StatelessWidget { _removeTodo(context, todo); }, onTap: () { - Navigator.of(context).push( + Navigator.of(context).push( MaterialPageRoute( builder: (_) { return DetailScreen( @@ -70,7 +67,7 @@ class TodoList extends StatelessWidget { void _removeTodo(BuildContext context, Todo todo) { removeTodo(todo); - Scaffold.of(context).showSnackBar( + ScaffoldMessenger.of(context).showSnackBar( SnackBar( key: ArchSampleKeys.snackbar, duration: Duration(seconds: 2), diff --git a/vanilla/lib/widgets/typedefs.dart b/vanilla/lib/widgets/typedefs.dart index 841d0414..5bd12aac 100644 --- a/vanilla/lib/widgets/typedefs.dart +++ b/vanilla/lib/widgets/typedefs.dart @@ -1,17 +1,14 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:vanilla/models.dart'; typedef TodoAdder = void Function(Todo todo); typedef TodoRemover = void Function(Todo todo); -typedef TodoUpdater = void Function( - Todo todo, { - bool complete, - String id, - String note, - String task, -}); +typedef TodoUpdater = + void Function( + Todo todo, { + bool complete, + String id, + String note, + String task, + }); diff --git a/vanilla/linux/.gitignore b/vanilla/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/vanilla/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/vanilla/linux/CMakeLists.txt b/vanilla/linux/CMakeLists.txt new file mode 100644 index 00000000..07bda46f --- /dev/null +++ b/vanilla/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +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 "vanilla") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.vanilla") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +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() + +# 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() + +# 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_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# 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 +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# 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() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +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) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/vanilla/linux/flutter/CMakeLists.txt b/vanilla/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/vanilla/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +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. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# 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/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter 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. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/vanilla/linux/flutter/generated_plugin_registrant.cc b/vanilla/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..e71a16d2 --- /dev/null +++ b/vanilla/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/vanilla/linux/flutter/generated_plugin_registrant.h b/vanilla/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/vanilla/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/vanilla/linux/flutter/generated_plugins.cmake b/vanilla/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..2e1de87a --- /dev/null +++ b/vanilla/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + 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}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/vanilla/linux/runner/CMakeLists.txt b/vanilla/linux/runner/CMakeLists.txt new file mode 100644 index 00000000..e97dabc7 --- /dev/null +++ b/vanilla/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "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 +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/vanilla/linux/runner/main.cc b/vanilla/linux/runner/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/vanilla/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/vanilla/linux/runner/my_application.cc b/vanilla/linux/runner/my_application.cc new file mode 100644 index 00000000..e464f86e --- /dev/null +++ b/vanilla/linux/runner/my_application.cc @@ -0,0 +1,144 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView *view) +{ + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // 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 + // desktop). + // 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. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "vanilla"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "vanilla"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/vanilla/linux/runner/my_application.h b/vanilla/linux/runner/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/vanilla/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/vanilla/macos/.gitignore b/vanilla/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/vanilla/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/vanilla/macos/Flutter/Flutter-Debug.xcconfig b/vanilla/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/vanilla/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/vanilla/macos/Flutter/Flutter-Release.xcconfig b/vanilla/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/vanilla/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/vanilla/macos/Flutter/GeneratedPluginRegistrant.swift b/vanilla/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b8e2b22f --- /dev/null +++ b/vanilla/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import path_provider_foundation +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/vanilla/macos/Podfile b/vanilla/macos/Podfile new file mode 100644 index 00000000..ff5ddb3b --- /dev/null +++ b/vanilla/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/vanilla/macos/Podfile.lock b/vanilla/macos/Podfile.lock new file mode 100644 index 00000000..d2f9a639 --- /dev/null +++ b/vanilla/macos/Podfile.lock @@ -0,0 +1,30 @@ +PODS: + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + +SPEC CHECKSUMS: + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.16.2 diff --git a/vanilla/macos/Runner.xcodeproj/project.pbxproj b/vanilla/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..057ff1e4 --- /dev/null +++ b/vanilla/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 0DB0F2570C55B0B797788C08 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9343CBAD94747D7ACB4EB50E /* Pods_Runner.framework */; }; + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 40D460CB6F26FFBA4EB68555 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EFD772974F837840962A580A /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 052C4455B2AD92DECBAF85B9 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* vanilla.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = vanilla.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 3D768DE9A14B5F7F18A1429B /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9343CBAD94747D7ACB4EB50E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + D4E88A8FC328CF8087B1DDAC /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + DE7158C3C2DA06E08F2E5DE0 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + EFD772974F837840962A580A /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F056FBB9B24E5793CCFB83FF /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + F2010033FF59ECE89969AD6D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 40D460CB6F26FFBA4EB68555 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0DB0F2570C55B0B797788C08 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + F1FD6A42FBE6DC914350D881 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* vanilla.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 9343CBAD94747D7ACB4EB50E /* Pods_Runner.framework */, + EFD772974F837840962A580A /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + F1FD6A42FBE6DC914350D881 /* Pods */ = { + isa = PBXGroup; + children = ( + F2010033FF59ECE89969AD6D /* Pods-Runner.debug.xcconfig */, + DE7158C3C2DA06E08F2E5DE0 /* Pods-Runner.release.xcconfig */, + D4E88A8FC328CF8087B1DDAC /* Pods-Runner.profile.xcconfig */, + 052C4455B2AD92DECBAF85B9 /* Pods-RunnerTests.debug.xcconfig */, + F056FBB9B24E5793CCFB83FF /* Pods-RunnerTests.release.xcconfig */, + 3D768DE9A14B5F7F18A1429B /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + DACAACDA87E72AD922CB1967 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + DA360F432763FB605CF70BFF /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 20634B7A4D35A646544E2307 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* vanilla.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 20634B7A4D35A646544E2307 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + DA360F432763FB605CF70BFF /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + DACAACDA87E72AD922CB1967 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 052C4455B2AD92DECBAF85B9 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.vanilla.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/vanilla.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/vanilla"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F056FBB9B24E5793CCFB83FF /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.vanilla.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/vanilla.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/vanilla"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3D768DE9A14B5F7F18A1429B /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.vanilla.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/vanilla.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/vanilla"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/vanilla/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/vanilla/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/vanilla/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/vanilla/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/vanilla/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..5aef3c77 --- /dev/null +++ b/vanilla/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vanilla/macos/Runner.xcworkspace/contents.xcworkspacedata b/vanilla/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/vanilla/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/vanilla/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/vanilla/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/vanilla/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/vanilla/macos/Runner/AppDelegate.swift b/vanilla/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..b3c17614 --- /dev/null +++ b/vanilla/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..82b6f9d9 Binary files /dev/null and b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..13b35eba Binary files /dev/null and b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..0a3f5fa4 Binary files /dev/null and b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bdb57226 Binary files /dev/null and b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..f083318e Binary files /dev/null and b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..326c0e72 Binary files /dev/null and b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..2f1632cf Binary files /dev/null and b/vanilla/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/vanilla/macos/Runner/Base.lproj/MainMenu.xib b/vanilla/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..80e867a4 --- /dev/null +++ b/vanilla/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vanilla/macos/Runner/Configs/AppInfo.xcconfig b/vanilla/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..09113f2a --- /dev/null +++ b/vanilla/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// 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 +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = vanilla + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.vanilla + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/vanilla/macos/Runner/Configs/Debug.xcconfig b/vanilla/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/vanilla/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/vanilla/macos/Runner/Configs/Release.xcconfig b/vanilla/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/vanilla/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/vanilla/macos/Runner/Configs/Warnings.xcconfig b/vanilla/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/vanilla/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/vanilla/macos/Runner/DebugProfile.entitlements b/vanilla/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..dddb8a30 --- /dev/null +++ b/vanilla/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/vanilla/macos/Runner/Info.plist b/vanilla/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/vanilla/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/vanilla/macos/Runner/MainFlutterWindow.swift b/vanilla/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/vanilla/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/vanilla/macos/Runner/Release.entitlements b/vanilla/macos/Runner/Release.entitlements new file mode 100644 index 00000000..852fa1a4 --- /dev/null +++ b/vanilla/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/vanilla/macos/RunnerTests/RunnerTests.swift b/vanilla/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/vanilla/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // 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. + } + +} diff --git a/vanilla/pubspec.yaml b/vanilla/pubspec.yaml index c168de5c..e42d6281 100644 --- a/vanilla/pubspec.yaml +++ b/vanilla/pubspec.yaml @@ -1,5 +1,8 @@ name: vanilla -description: A new Flutter project. +description: "A new Flutter project." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: "none" # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -8,41 +11,49 @@ description: A new Flutter project. # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. version: 1.0.0+1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ^3.9.0 +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter + shared_preferences: todos_app_core: path: ../todos_app_core + todos_repository_core: + path: ../todos_repository_core todos_repository_local_storage: path: ../todos_repository_local_storage - key_value_store_flutter: - key_value_store_web: - shared_preferences: dev_dependencies: + flutter_lints: flutter_test: sdk: flutter - flutter_driver: + integration_test: sdk: flutter - test: - mockito: integration_tests: path: ../integration_tests + mockito: + test: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec -# The following section is specific to Flutter. +# The following section is specific to Flutter packages. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. @@ -50,14 +61,14 @@ flutter: # To add assets to your application, add an assets section, like this: # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. + # https://flutter.dev/to/resolution-aware-images # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages + # https://flutter.dev/to/asset-from-package # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a @@ -77,4 +88,4 @@ flutter: # weight: 700 # # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages + # see https://flutter.dev/to/font-from-package diff --git a/vanilla/test/app_state_test.dart b/vanilla/test/app_state_test.dart index f9cb59cb..3ea46731 100644 --- a/vanilla/test/app_state_test.dart +++ b/vanilla/test/app_state_test.dart @@ -1,51 +1,35 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - import 'package:test/test.dart'; import 'package:vanilla/models.dart'; void main() { group('AppState', () { test('should check if there are completed todos', () { - final state = AppState(todos: [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]); + final state = AppState( + todos: [Todo('a'), Todo('b'), Todo('c', complete: true)], + ); expect(state.hasCompletedTodos, true); }); test('should calculate the number of active todos', () { - final state = AppState(todos: [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]); + final state = AppState( + todos: [Todo('a'), Todo('b'), Todo('c', complete: true)], + ); expect(state.numActive, 2); }); test('should calculate the number of completed todos', () { - final state = AppState(todos: [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]); + final state = AppState( + todos: [Todo('a'), Todo('b'), Todo('c', complete: true)], + ); expect(state.numCompleted, 1); }); test('should return all todos if the VisibilityFilter is all', () { - final todos = [ - Todo('a'), - Todo('b'), - Todo('c', complete: true), - ]; - final state = AppState( - todos: todos, - ); + final todos = [Todo('a'), Todo('b'), Todo('c', complete: true)]; + final state = AppState(todos: todos); expect(state.filteredTodos(VisibilityFilter.all), todos); }); @@ -54,71 +38,43 @@ void main() { final todo1 = Todo('a'); final todo2 = Todo('b'); final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final state = AppState( - todos: todos, - ); + final todos = [todo1, todo2, todo3]; + final state = AppState(todos: todos); - expect(state.filteredTodos(VisibilityFilter.active), [ - todo1, - todo2, - ]); + expect(state.filteredTodos(VisibilityFilter.active), [todo1, todo2]); }); - test('should return completed todos if the VisibilityFilter is completed', - () { - final todo1 = Todo('a'); - final todo2 = Todo('b'); - final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final state = AppState( - todos: todos, - ); + test( + 'should return completed todos if the VisibilityFilter is completed', + () { + final todo1 = Todo('a'); + final todo2 = Todo('b'); + final todo3 = Todo('c', complete: true); + final todos = [todo1, todo2, todo3]; + final state = AppState(todos: todos); - expect(state.filteredTodos(VisibilityFilter.completed), [todo3]); - }); + expect(state.filteredTodos(VisibilityFilter.completed), [todo3]); + }, + ); test('should clear the completed todos', () { final todo1 = Todo('a'); final todo2 = Todo('b'); final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final state = AppState( - todos: todos, - ); + final todos = [todo1, todo2, todo3]; + final state = AppState(todos: todos); state.clearCompleted(); - expect(state.todos, [ - todo1, - todo2, - ]); + expect(state.todos, [todo1, todo2]); }); test('toggle all as complete or incomplete', () { final todo1 = Todo('a'); final todo2 = Todo('b'); final todo3 = Todo('c', complete: true); - final todos = [ - todo1, - todo2, - todo3, - ]; - final state = AppState( - todos: todos, - ); + final todos = [todo1, todo2, todo3]; + final state = AppState(todos: todos); // Toggle all complete state.toggleAll(); diff --git a/vanilla/test_driver/integration_test.dart b/vanilla/test_driver/integration_test.dart new file mode 100644 index 00000000..b38629cc --- /dev/null +++ b/vanilla/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/vanilla/test_driver/todo_app.dart b/vanilla/test_driver/todo_app.dart deleted file mode 100644 index 36be3ffc..00000000 --- a/vanilla/test_driver/todo_app.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -// This line imports the extension -import 'package:flutter_driver/driver_extension.dart'; -import 'package:vanilla/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - - app.main(); -} diff --git a/vanilla/test_driver/todo_app_test.dart b/vanilla/test_driver/todo_app_test.dart deleted file mode 100644 index ad93f5a5..00000000 --- a/vanilla/test_driver/todo_app_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Flutter Architecture Sample Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be found -// in the LICENSE file. - -import 'package:integration_tests/integration_tests.dart' as integration_tests; - -void main() { - integration_tests.main(); -} diff --git a/vanilla/web/favicon.png b/vanilla/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/vanilla/web/favicon.png differ diff --git a/vanilla/web/icons/Icon-192.png b/vanilla/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/vanilla/web/icons/Icon-192.png differ diff --git a/vanilla/web/icons/Icon-512.png b/vanilla/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/vanilla/web/icons/Icon-512.png differ diff --git a/vanilla/web/icons/Icon-maskable-192.png b/vanilla/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/vanilla/web/icons/Icon-maskable-192.png differ diff --git a/vanilla/web/icons/Icon-maskable-512.png b/vanilla/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/vanilla/web/icons/Icon-maskable-512.png differ diff --git a/vanilla/web/index.html b/vanilla/web/index.html index 6215e093..2bd5d10d 100644 --- a/vanilla/web/index.html +++ b/vanilla/web/index.html @@ -1,10 +1,38 @@ + + + + + + + + + + + + + + + vanilla + - + diff --git a/vanilla/web/manifest.json b/vanilla/web/manifest.json new file mode 100644 index 00000000..13e3c5c8 --- /dev/null +++ b/vanilla/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "vanilla", + "short_name": "vanilla", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/vanilla/windows/.gitignore b/vanilla/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/vanilla/windows/.gitignore @@ -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/ diff --git a/vanilla/windows/CMakeLists.txt b/vanilla/windows/CMakeLists.txt new file mode 100644 index 00000000..5b958da5 --- /dev/null +++ b/vanilla/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(vanilla 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 "vanilla") + +# 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) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_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 "$") +# 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) diff --git a/vanilla/windows/flutter/CMakeLists.txt b/vanilla/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..903f4899 --- /dev/null +++ b/vanilla/windows/flutter/CMakeLists.txt @@ -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} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/vanilla/windows/flutter/generated_plugin_registrant.cc b/vanilla/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..8b6d4680 --- /dev/null +++ b/vanilla/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/vanilla/windows/flutter/generated_plugin_registrant.h b/vanilla/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/vanilla/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/vanilla/windows/flutter/generated_plugins.cmake b/vanilla/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..b93c4c30 --- /dev/null +++ b/vanilla/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +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 $) + 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) diff --git a/vanilla/windows/runner/CMakeLists.txt b/vanilla/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/vanilla/windows/runner/CMakeLists.txt @@ -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) diff --git a/vanilla/windows/runner/Runner.rc b/vanilla/windows/runner/Runner.rc new file mode 100644 index 00000000..f726acb7 --- /dev/null +++ b/vanilla/windows/runner/Runner.rc @@ -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", "com.example" "\0" + VALUE "FileDescription", "vanilla" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "vanilla" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "vanilla.exe" "\0" + VALUE "ProductName", "vanilla" "\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 diff --git a/vanilla/windows/runner/flutter_window.cpp b/vanilla/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..955ee303 --- /dev/null +++ b/vanilla/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#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( + 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 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); +} diff --git a/vanilla/windows/runner/flutter_window.h b/vanilla/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/vanilla/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#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_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/vanilla/windows/runner/main.cpp b/vanilla/windows/runner/main.cpp new file mode 100644 index 00000000..c06a5fe3 --- /dev/null +++ b/vanilla/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 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"vanilla", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/vanilla/windows/runner/resource.h b/vanilla/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/vanilla/windows/runner/resource.h @@ -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 diff --git a/vanilla/windows/runner/resources/app_icon.ico b/vanilla/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/vanilla/windows/runner/resources/app_icon.ico differ diff --git a/vanilla/windows/runner/runner.exe.manifest b/vanilla/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..153653e8 --- /dev/null +++ b/vanilla/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/vanilla/windows/runner/utils.cpp b/vanilla/windows/runner/utils.cpp new file mode 100644 index 00000000..3a0b4651 --- /dev/null +++ b/vanilla/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +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 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::vector 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; +} diff --git a/vanilla/windows/runner/utils.h b/vanilla/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/vanilla/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// 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, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/vanilla/windows/runner/win32_window.cpp b/vanilla/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/vanilla/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#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(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( + 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(origin.x), + static_cast(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(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(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(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( + 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)); + } +} diff --git a/vanilla/windows/runner/win32_window.h b/vanilla/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/vanilla/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// 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_