diff --git a/.fvmrc b/.fvmrc new file mode 100644 index 0000000..df27a83 --- /dev/null +++ b/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "3.7.12" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b6178e0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,53 @@ +# 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/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# 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 + +*.sketch + +# FVM Version Cache +.fvm/ + +/lib/Secrets.dart \ No newline at end of file diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..fd70cab --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: 77d935af4db863f6abd0b9c31c7e6df2a13de57b + channel: stable + +project_type: app diff --git a/README.md b/README.md new file mode 100644 index 0000000..e5b7ef2 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# Classic 2048 Game + +## Overview + +Classic 2048 is a mobile puzzle game inspired by the original 2048 game developed by Flutter. The objective is to slide numbered tiles on a grid to combine them and create a tile with the number 2048. + +[Available on Google Play](https://play.google.com/store/apps/details?id=com.appsbay.classic_2048) + +## Features + +- **Multiple Grid Sizes**: Choose from 4x4, 5x5, and 6x6 grids for different levels of difficulty. +- **Random and Shuffle Options**: Mix up the tiles with Random and Shuffle buttons to add an extra challenge. +- **Beautiful Backgrounds**: Enjoy stunning background images as you play, inspired by nature and different scenic locations. +- **Smooth Animations**: Experience smooth and fluid animations that enhance gameplay. +- **User-friendly Interface**: Simple and intuitive UI design for an engaging user experience. + +## Screenshots + +

+iOS Screenshot +iOS Screenshot +

+ + + +## How to Play + +1. **Choose Game Mode**: Select your preferred grid size. +2. **Slide to Play**: Swipe in any direction to move the tiles. When two tiles with the same number touch, they merge into one. +3. **Aim for 2048**: Keep merging tiles until you create a tile with the number 2048. +4. **Use Shuffle and Random**: If you're stuck, use the Shuffle or Random buttons to mix up the board. + +## Contribution + +Feel free to fork this repository and submit pull requests. For major changes, please open an issue first to discuss what you would like to change. + +## License + +This project is licensed under the MIT License diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..61b6c4d --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,29 @@ +# 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 + +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-lang.github.io/linter/lints/index.html. + # + # 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/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..0ad53cc --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,90 @@ +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + +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' +} + +def AdMobAppId = localProperties.getProperty('AdMobAppId') +if (AdMobAppId == null) { + AdMobAppId = 'ca-app-pub-3940256099942544~3347511713' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 34 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.appsbay.classic_2048" + minSdkVersion 19 + targetSdkVersion 34 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + multiDexEnabled true + manifestPlaceholders = [AdMobAppId: AdMobAppId] + } + + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } + + 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.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..f88600e --- /dev/null +++ b/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c55d698 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/appsbay/classic_2048/MainActivity.kt b/android/app/src/main/kotlin/com/appsbay/classic_2048/MainActivity.kt new file mode 100644 index 0000000..c669276 --- /dev/null +++ b/android/app/src/main/kotlin/com/appsbay/classic_2048/MainActivity.kt @@ -0,0 +1,6 @@ +package com.appsbay.classic_2048 + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/android/app/src/main/res/drawable-hdpi/splash.png b/android/app/src/main/res/drawable-hdpi/splash.png new file mode 100644 index 0000000..da7dc23 Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-mdpi/splash.png b/android/app/src/main/res/drawable-mdpi/splash.png new file mode 100644 index 0000000..1f6c41d Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-v21/background.png b/android/app/src/main/res/drawable-v21/background.png new file mode 100644 index 0000000..c60c28f Binary files /dev/null and b/android/app/src/main/res/drawable-v21/background.png differ diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..3fe6b2e --- /dev/null +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable-xhdpi/splash.png b/android/app/src/main/res/drawable-xhdpi/splash.png new file mode 100644 index 0000000..51c4cb8 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/splash.png b/android/app/src/main/res/drawable-xxhdpi/splash.png new file mode 100644 index 0000000..a8b9e46 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/splash.png b/android/app/src/main/res/drawable-xxxhdpi/splash.png new file mode 100644 index 0000000..485762b Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable/background.png b/android/app/src/main/res/drawable/background.png new file mode 100644 index 0000000..c60c28f Binary files /dev/null and b/android/app/src/main/res/drawable/background.png differ diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..3fe6b2e --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png new file mode 100644 index 0000000..c6d5b23 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png new file mode 100644 index 0000000..27589d7 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png new file mode 100644 index 0000000..c898af8 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png new file mode 100644 index 0000000..f3c80c3 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png new file mode 100644 index 0000000..b48815f Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..3db14bb --- /dev/null +++ b/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/main/res/values-zh-rCN/strings.xml b/android/app/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000..1102945 --- /dev/null +++ b/android/app/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,4 @@ + + + 经典 2048 + \ No newline at end of file diff --git a/android/app/src/main/res/values-zh-rHK/strings.xml b/android/app/src/main/res/values-zh-rHK/strings.xml new file mode 100644 index 0000000..7ded6ea --- /dev/null +++ b/android/app/src/main/res/values-zh-rHK/strings.xml @@ -0,0 +1,4 @@ + + + 經典 2048 + \ No newline at end of file diff --git a/android/app/src/main/res/values-zh-rTW/strings.xml b/android/app/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000..7ded6ea --- /dev/null +++ b/android/app/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,4 @@ + + + 經典 2048 + \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..ba48da3 --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + 2048 Lover + \ No newline at end of file diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..e929412 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..8b170ad --- /dev/null +++ b/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..6032b3d --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,32 @@ +buildscript { + ext.kotlin_version = '1.9.20' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.2.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..4d3226a --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..7d17699 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#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-7.3.3-all.zip \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/assets/app_icon.png b/assets/app_icon.png new file mode 100644 index 0000000..13ca232 Binary files /dev/null and b/assets/app_icon.png differ diff --git a/assets/image/bg.jpg b/assets/image/bg.jpg new file mode 100644 index 0000000..ba081e0 Binary files /dev/null and b/assets/image/bg.jpg differ diff --git a/assets/image/bg1.jpg b/assets/image/bg1.jpg new file mode 100644 index 0000000..fcd5c59 Binary files /dev/null and b/assets/image/bg1.jpg differ diff --git a/assets/image/bg2.jpg b/assets/image/bg2.jpg new file mode 100644 index 0000000..3268e06 Binary files /dev/null and b/assets/image/bg2.jpg differ diff --git a/assets/image/bg3.jpg b/assets/image/bg3.jpg new file mode 100644 index 0000000..1f00be1 Binary files /dev/null and b/assets/image/bg3.jpg differ diff --git a/assets/image/bg4.jpg b/assets/image/bg4.jpg new file mode 100644 index 0000000..02abee0 Binary files /dev/null and b/assets/image/bg4.jpg differ diff --git a/assets/image/bg5.jpg b/assets/image/bg5.jpg new file mode 100644 index 0000000..8ed55bf Binary files /dev/null and b/assets/image/bg5.jpg differ diff --git a/flutter_native_splash.yaml b/flutter_native_splash.yaml new file mode 100644 index 0000000..61bfb18 --- /dev/null +++ b/flutter_native_splash.yaml @@ -0,0 +1,3 @@ +flutter_native_splash: + color: "#373C69" + image: assets/app_icon.png \ No newline at end of file diff --git a/images/game_mode.webp b/images/game_mode.webp new file mode 100644 index 0000000..94142f5 Binary files /dev/null and b/images/game_mode.webp differ diff --git a/images/game_play.webp b/images/game_play.webp new file mode 100644 index 0000000..67e3fd2 Binary files /dev/null and b/images/game_play.webp differ diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..83f53eb --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,36 @@ +**/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 + +Runner/Secret.xcconfig diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..9625e10 --- /dev/null +++ b/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 + 11.0 + + diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/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/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/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/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..88359b2 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '11.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! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..4175443 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,125 @@ +PODS: + - app_tracking_transparency (0.0.1): + - Flutter + - Flutter (1.0.0) + - fluttertoast (0.0.2): + - Flutter + - Toast + - Google-Mobile-Ads-SDK (8.11.0): + - GoogleAppMeasurement (< 9.0, >= 7.0) + - GoogleUserMessagingPlatform (>= 1.1) + - google_mobile_ads (0.0.1): + - Flutter + - Google-Mobile-Ads-SDK (= 8.11.0) + - GoogleAppMeasurement (8.12.0): + - GoogleAppMeasurement/AdIdSupport (= 8.12.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.7) + - GoogleUtilities/MethodSwizzler (~> 7.7) + - GoogleUtilities/Network (~> 7.7) + - "GoogleUtilities/NSData+zlib (~> 7.7)" + - nanopb (~> 2.30908.0) + - GoogleAppMeasurement/AdIdSupport (8.12.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 8.12.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.7) + - GoogleUtilities/MethodSwizzler (~> 7.7) + - GoogleUtilities/Network (~> 7.7) + - "GoogleUtilities/NSData+zlib (~> 7.7)" + - nanopb (~> 2.30908.0) + - GoogleAppMeasurement/WithoutAdIdSupport (8.12.0): + - GoogleUtilities/AppDelegateSwizzler (~> 7.7) + - GoogleUtilities/MethodSwizzler (~> 7.7) + - GoogleUtilities/Network (~> 7.7) + - "GoogleUtilities/NSData+zlib (~> 7.7)" + - nanopb (~> 2.30908.0) + - GoogleUserMessagingPlatform (2.0.0) + - GoogleUtilities/AppDelegateSwizzler (7.7.0): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.7.0): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.7.0): + - GoogleUtilities/Environment + - GoogleUtilities/MethodSwizzler (7.7.0): + - GoogleUtilities/Logger + - GoogleUtilities/Network (7.7.0): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.7.0)" + - GoogleUtilities/Reachability (7.7.0): + - GoogleUtilities/Logger + - in_app_review (0.2.0): + - Flutter + - launch_review (0.0.1): + - Flutter + - nanopb (2.30908.0): + - nanopb/decode (= 2.30908.0) + - nanopb/encode (= 2.30908.0) + - nanopb/decode (2.30908.0) + - nanopb/encode (2.30908.0) + - PromisesObjC (2.0.0) + - shared_preferences_ios (0.0.1): + - Flutter + - Toast (4.0.0) + - url_launcher_ios (0.0.1): + - Flutter + +DEPENDENCIES: + - app_tracking_transparency (from `.symlinks/plugins/app_tracking_transparency/ios`) + - Flutter (from `Flutter`) + - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) + - google_mobile_ads (from `.symlinks/plugins/google_mobile_ads/ios`) + - in_app_review (from `.symlinks/plugins/in_app_review/ios`) + - launch_review (from `.symlinks/plugins/launch_review/ios`) + - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + +SPEC REPOS: + trunk: + - Google-Mobile-Ads-SDK + - GoogleAppMeasurement + - GoogleUserMessagingPlatform + - GoogleUtilities + - nanopb + - PromisesObjC + - Toast + +EXTERNAL SOURCES: + app_tracking_transparency: + :path: ".symlinks/plugins/app_tracking_transparency/ios" + Flutter: + :path: Flutter + fluttertoast: + :path: ".symlinks/plugins/fluttertoast/ios" + google_mobile_ads: + :path: ".symlinks/plugins/google_mobile_ads/ios" + in_app_review: + :path: ".symlinks/plugins/in_app_review/ios" + launch_review: + :path: ".symlinks/plugins/launch_review/ios" + shared_preferences_ios: + :path: ".symlinks/plugins/shared_preferences_ios/ios" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" + +SPEC CHECKSUMS: + app_tracking_transparency: 5b1745ef9ade815f7455cb6a0848349589afb7c5 + Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + fluttertoast: 6122fa75143e992b1d3470f61000f591a798cc58 + Google-Mobile-Ads-SDK: be2192b51b74d74a6ed70590c2e8275412f1b71e + google_mobile_ads: a2f8b901601401bf7e691b4224d5992e9a37599a + GoogleAppMeasurement: ae033c3aad67e68294369373056b4d74cc8ae0d6 + GoogleUserMessagingPlatform: ab890ce5f6620f293a21b6bdd82e416a2c73aeca + GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 + in_app_review: 4a97249f7a2f539a0f294c2d9196b7fe35e49541 + launch_review: 75d5a956ba8eaa493e9c9d4bf4c05e505e8d5ed0 + nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 + PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 + shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad + Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 + url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de + +PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 + +COCOAPODS: 1.15.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..4e6c225 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,589 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + 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 */; }; + 4178031727BFC6A4002D2861 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4178031927BFC6A4002D2861 /* InfoPlist.strings */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 91444388EE23BC1731F7926A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1956B1FF1CBC31EDB518FE4A /* Pods_Runner.framework */; }; + 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 = ( + ); + 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 = ""; }; + 1956B1FF1CBC31EDB518FE4A /* 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 = ""; }; + 4178031127BFC660002D2861 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Main.strings"; sourceTree = ""; }; + 4178031227BFC661002D2861 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/LaunchScreen.strings"; sourceTree = ""; }; + 4178031327BFC664002D2861 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Main.strings"; sourceTree = ""; }; + 4178031427BFC664002D2861 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/LaunchScreen.strings"; sourceTree = ""; }; + 4178031827BFC6A4002D2861 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 4178031A27BFC6A6002D2861 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; + 4178031B27BFC6A7002D2861 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; 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 = ""; }; + 794AE7632EAA1FD6FC210E9C /* 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 = ""; }; + 7A3307B9D4040F5A73D6FFC3 /* 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 = ""; }; + 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 = ""; }; + 9949A91C2C7F4D560027C480 /* Secret.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Secret.xcconfig; sourceTree = ""; }; + D1997A15008B3E551060C028 /* 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 = ( + 91444388EE23BC1731F7926A /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 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 */, + B96C1C2CC292A06F895751B8 /* Pods */, + A9FC0A7B8153754F873079FA /* Frameworks */, + ); + 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 */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + 4178031927BFC6A4002D2861 /* InfoPlist.strings */, + 9949A91C2C7F4D560027C480 /* Secret.xcconfig */, + ); + path = Runner; + sourceTree = ""; + }; + A9FC0A7B8153754F873079FA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1956B1FF1CBC31EDB518FE4A /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + B96C1C2CC292A06F895751B8 /* Pods */ = { + isa = PBXGroup; + children = ( + 7A3307B9D4040F5A73D6FFC3 /* Pods-Runner.debug.xcconfig */, + 794AE7632EAA1FD6FC210E9C /* Pods-Runner.release.xcconfig */, + D1997A15008B3E551060C028 /* Pods-Runner.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 77549FE1392C04D8C83FB971 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 4F5C626FC0EEB65A52D8911E /* [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 = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 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, + "zh-Hans", + "zh-Hant", + ); + 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 */, + 4178031727BFC6A4002D2861 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + 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\" embed_and_thin"; + }; + 4F5C626FC0EEB65A52D8911E /* [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; + }; + 77549FE1392C04D8C83FB971 /* [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; + }; + 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 */ + 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 */ + 4178031927BFC6A4002D2861 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 4178031827BFC6A4002D2861 /* en */, + 4178031A27BFC6A6002D2861 /* zh-Hans */, + 4178031B27BFC6A7002D2861 /* zh-Hant */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + 4178031127BFC660002D2861 /* zh-Hans */, + 4178031327BFC664002D2861 /* zh-Hant */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + 4178031227BFC661002D2861 /* zh-Hans */, + 4178031427BFC664002D2861 /* zh-Hant */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = 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; + 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 = 11.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 = F694X76A5X; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.appsbay.classic2048; + 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 = 9949A91C2C7F4D560027C480 /* Secret.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = 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; + 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 = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9949A91C2C7F4D560027C480 /* Secret.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = 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; + 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 = 11.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 = F694X76A5X; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.appsbay.classic2048; + 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 = F694X76A5X; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.appsbay.classic2048; + 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/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..c87d15a --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +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/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "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" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..485762b Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..bb5b415 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..58b70ac Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..bb11762 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..85ad367 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..6073818 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..5d5d3c1 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..58b70ac Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..c7fc7b1 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..cf159ae Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..cf159ae Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..9dbbf7b Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..c05a340 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..9e05dc0 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..84ed57e Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/BrandingImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/BrandingImage.imageset/Contents.json new file mode 100644 index 0000000..1271227 --- /dev/null +++ b/ios/Runner/Assets.xcassets/BrandingImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "BrandingImage.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "BrandingImage@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "BrandingImage@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json new file mode 100644 index 0000000..9f447e1 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "background.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png new file mode 100644 index 0000000..c60c28f Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..00cabce --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "LaunchImage.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "LaunchImage@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "LaunchImage@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..1f6c41d Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..51c4cb8 Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..a8b9e46 Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# 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/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..28f9d1b --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist new file mode 100644 index 0000000..fafa54d --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,216 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + 2048 Lover + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + classic_2048 + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + GADApplicationIdentifier + $(GAD_APPLICATION_IDENTIFIER) + LSApplicationQueriesSchemes + + https + http + + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSUserTrackingUsageDescription + This identifier will be used to deliver personalized ads to you. + SKAdNetworkItems + + + SKAdNetworkIdentifier + cstr6suwn9.skadnetwork + + + SKAdNetworkIdentifier + 4fzdc2evr5.skadnetwork + + + SKAdNetworkIdentifier + 2fnua5tdw4.skadnetwork + + + SKAdNetworkIdentifier + ydx93a7ass.skadnetwork + + + SKAdNetworkIdentifier + 5a6flpkh64.skadnetwork + + + SKAdNetworkIdentifier + p78axxw29g.skadnetwork + + + SKAdNetworkIdentifier + v72qych5uu.skadnetwork + + + SKAdNetworkIdentifier + c6k4g5qg8m.skadnetwork + + + SKAdNetworkIdentifier + s39g8k73mm.skadnetwork + + + SKAdNetworkIdentifier + 3qy4746246.skadnetwork + + + SKAdNetworkIdentifier + 3sh42y64q3.skadnetwork + + + SKAdNetworkIdentifier + f38h382jlk.skadnetwork + + + SKAdNetworkIdentifier + hs6bdukanm.skadnetwork + + + SKAdNetworkIdentifier + prcb7njmu6.skadnetwork + + + SKAdNetworkIdentifier + v4nxqhlyqp.skadnetwork + + + SKAdNetworkIdentifier + wzmmz9fp6w.skadnetwork + + + SKAdNetworkIdentifier + yclnxrl5pm.skadnetwork + + + SKAdNetworkIdentifier + t38b2kh725.skadnetwork + + + SKAdNetworkIdentifier + 7ug5zh24hu.skadnetwork + + + SKAdNetworkIdentifier + 9rd848q2bz.skadnetwork + + + SKAdNetworkIdentifier + n6fk4nfna4.skadnetwork + + + SKAdNetworkIdentifier + kbd757ywx3.skadnetwork + + + SKAdNetworkIdentifier + 9t245vhmpl.skadnetwork + + + SKAdNetworkIdentifier + 4468km3ulz.skadnetwork + + + SKAdNetworkIdentifier + 2u9pt9hc89.skadnetwork + + + SKAdNetworkIdentifier + 8s468mfl3y.skadnetwork + + + SKAdNetworkIdentifier + av6w8kgt66.skadnetwork + + + SKAdNetworkIdentifier + klf5c3l5u5.skadnetwork + + + SKAdNetworkIdentifier + ppxm28t8ap.skadnetwork + + + SKAdNetworkIdentifier + 424m5254lk.skadnetwork + + + SKAdNetworkIdentifier + uw77j35x4d.skadnetwork + + + SKAdNetworkIdentifier + 578prtvx9j.skadnetwork + + + SKAdNetworkIdentifier + 4dzt52r2t5.skadnetwork + + + SKAdNetworkIdentifier + e5fvkxwrpn.skadnetwork + + + SKAdNetworkIdentifier + 8c4e2ghe7u.skadnetwork + + + SKAdNetworkIdentifier + zq492l623r.skadnetwork + + + SKAdNetworkIdentifier + 3qcr597p9d.skadnetwork + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/ios/Runner/en.lproj/InfoPlist.strings b/ios/Runner/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..16106ce --- /dev/null +++ b/ios/Runner/en.lproj/InfoPlist.strings @@ -0,0 +1,9 @@ +/* + InfoPlist.strings + Runner + + Created by Lulin Y on 2022/2/18. + +*/ + +CFBundleDisplayName = "2048 Lover"; diff --git a/ios/Runner/zh-Hans.lproj/InfoPlist.strings b/ios/Runner/zh-Hans.lproj/InfoPlist.strings new file mode 100644 index 0000000..1ede6b7 --- /dev/null +++ b/ios/Runner/zh-Hans.lproj/InfoPlist.strings @@ -0,0 +1,9 @@ +/* + InfoPlist.strings + Runner + + Created by Lulin Y on 2022/2/18. + +*/ + +CFBundleDisplayName = "经典 2048"; diff --git a/ios/Runner/zh-Hans.lproj/LaunchScreen.strings b/ios/Runner/zh-Hans.lproj/LaunchScreen.strings new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ios/Runner/zh-Hans.lproj/LaunchScreen.strings @@ -0,0 +1 @@ + diff --git a/ios/Runner/zh-Hans.lproj/Main.strings b/ios/Runner/zh-Hans.lproj/Main.strings new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ios/Runner/zh-Hans.lproj/Main.strings @@ -0,0 +1 @@ + diff --git a/ios/Runner/zh-Hant.lproj/InfoPlist.strings b/ios/Runner/zh-Hant.lproj/InfoPlist.strings new file mode 100644 index 0000000..66f659e --- /dev/null +++ b/ios/Runner/zh-Hant.lproj/InfoPlist.strings @@ -0,0 +1,9 @@ +/* + InfoPlist.strings + Runner + + Created by Lulin Y on 2022/2/18. + +*/ + +CFBundleDisplayName = "經典 2048"; diff --git a/ios/Runner/zh-Hant.lproj/LaunchScreen.strings b/ios/Runner/zh-Hant.lproj/LaunchScreen.strings new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ios/Runner/zh-Hant.lproj/LaunchScreen.strings @@ -0,0 +1 @@ + diff --git a/ios/Runner/zh-Hant.lproj/Main.strings b/ios/Runner/zh-Hant.lproj/Main.strings new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ios/Runner/zh-Hant.lproj/Main.strings @@ -0,0 +1 @@ + diff --git a/lib/game_page.dart b/lib/game_page.dart new file mode 100644 index 0000000..b18b6a9 --- /dev/null +++ b/lib/game_page.dart @@ -0,0 +1,601 @@ +import 'dart:math'; + +import 'package:classic_2048/game_pause_cover.dart'; +import 'package:classic_2048/util/ads_manager.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_neumorphic/flutter_neumorphic.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +import 'generated/l10n.dart'; +import 'logic.dart'; +import 'main.dart'; + +class GamePage extends StatelessWidget { + int row; + int newNum; + String bg; + + GamePage({Key? key, required this.row, required this.newNum, required this.bg}) : super(key: key); + + @override + Widget build(BuildContext context) { + double height = MediaQuery.of(context).size.height; + double width = MediaQuery.of(context).size.width; + double safePadding = MediaQuery.of(context).padding.top + MediaQuery.of(context).padding.bottom; + double widthFinal = width; + + double marginWidth = 10; + if (width >= 600) { + marginWidth = max(width * 0.1, (width - 600) / 2); + widthFinal = width - marginWidth * 2 + 20; + } + + double barHeight = max(height - widthFinal - safePadding - 160, 1); + + return Scaffold( + appBar: PreferredSize( + preferredSize: Size.fromHeight(barHeight), + child: AppBar( + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: Icon( + Icons.arrow_back_rounded, + ), + ), + flexibleSpace: InkWell( + onTap: () { + Navigator.push( + context, MaterialPageRoute(builder: (context) => GamePauseCoverPage(bg: bg))); + }, + child: Image( + image: AssetImage('assets/image/$bg.jpg'), + fit: BoxFit.cover, + ), + ), + backgroundColor: Colors.transparent, + elevation: 0, + actions: [ + // IconButton( + // icon: Icon(Icons.info_outline), + // onPressed: () { + // // return _aboutDialogAction(context); + // }, + // ) + ]), + ), + backgroundColor: Color(0xff47507C), + body: GameWidget( + row: row, + newNum: newNum, + ), + ); + } +} + +class BoardGridWidget extends StatelessWidget { + final _GameWidgetState _state; + BoardGridWidget(this._state); + @override + Widget build(BuildContext context) { + final boardSize = _state.boardSize(); + double width = + (boardSize.width - 20 - (_state.column + 1) * _state.cellPadding) / _state.column; + List _backgroundBox = []; + for (int r = 0; r < _state.row; ++r) { + for (int c = 0; c < _state.column; ++c) { + CellBox box = CellBox( + left: c * width + _state.cellPadding * (c + 1), + top: r * width + _state.cellPadding * (r + 1), + size: width, + shadowOffset: _state.shadowOffset, + color: Colors.white.withOpacity(0.1), + text: null, + ); + _backgroundBox.add(box); + } + } + return Positioned( + left: 0.0, + top: 0.0, + child: Container( + width: _state.boardSize().width, + height: _state.boardSize().height, + decoration: BoxDecoration( + border: Border.all(color: Color(0xff34415F), width: 10), + color: Color(0xff4C5B7D), + borderRadius: BorderRadius.all(Radius.circular(20.0)), + ), + child: Stack( + children: _backgroundBox, + ), + )); + } +} + +class GameWidget extends StatefulWidget { + int row; + int newNum; + + GameWidget({Key? key, required this.row, required this.newNum}) : super(key: key); + + @override + State createState() { + return _GameWidgetState(); + } +} + +class _GameWidgetState extends State { + late BannerAd _ad; + + bool _isAdLoaded = false; + + late Game _game; + late MediaQueryData _queryData; + int row = 4; + int column = 4; + int newNum = 1; + double cellPadding = 10.0; + double shadowOffset = 2; + EdgeInsets _gameMargin = EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0); + bool _isDragging = false; + bool _isGameOver = false; + + @override + void initState() { + _ad = BannerAd( + adUnitId: AdsManager.bannerAdUnitId, + size: AdSize.banner, + request: AdRequest(), + listener: BannerAdListener( + onAdLoaded: (_) { + setState(() { + _isAdLoaded = true; + }); + }, + onAdFailedToLoad: (ad, error) { + // Releases an ad resource when it fails to load + ad.dispose(); + + print('Ad load failed (code=${error.code} message=${error.message})'); + }, + ), + ); + + _ad.load(); + + super.initState(); + + row = widget.row; + column = widget.row; + newNum = widget.newNum; + + if (widget.row == 4) { + cellPadding = 15; + shadowOffset = 2; + } else if (widget.row == 5) { + cellPadding = 10; + shadowOffset = 1.5; + } else { + cellPadding = 8; + shadowOffset = 1; + } + + _game = Game(row, column, newNum); + newGame(); + } + + void newGame() { + _game.init(); + _isGameOver = false; + setState(() {}); + } + + void moveLeft() { + setState(() { + _game.moveLeft(); + checkGameOver(); + }); + } + + void moveRight() { + setState(() { + _game.moveRight(); + checkGameOver(); + }); + } + + void moveUp() { + setState(() { + _game.moveUp(); + checkGameOver(); + }); + } + + void moveDown() { + setState(() { + _game.moveDown(); + checkGameOver(); + }); + } + + void checkGameOver() { + if (_game.isGameOver()) { + _isGameOver = true; + Fluttertoast.showToast( + msg: S.of(context).Game_Over, + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.CENTER, + timeInSecForIosWeb: 1, + backgroundColor: Colors.black, + textColor: Colors.white, + fontSize: 16.0); + } + } + + @override + Widget build(BuildContext context) { + List _cellWidgets = []; + for (int r = 0; r < row; ++r) { + for (int c = 0; c < column; ++c) { + _cellWidgets.add(CellWidget(cell: _game.get(r, c), state: this)); + } + } + _queryData = MediaQuery.of(context); + + double width = _queryData.size.width; + double marginWidth = 10; + if (width >= 600) { + marginWidth = max(width * 0.1, (width - 600) / 2); + } + _gameMargin = EdgeInsets.fromLTRB(marginWidth, 0.0, marginWidth, 0.0); + + List children = []; + children.add(BoardGridWidget(this)); + children.addAll(_cellWidgets); + return SafeArea( + child: Column( + children: [ + Container( + margin: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 0.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Container( + height: 40.0, + child: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + S.of(context).Score + ": ", + style: TextStyle( + fontSize: 18.0, + color: Colors.white, + ), + ), + SizedBox( + height: 8, + ), + Text( + _game.score.toString(), + style: TextStyle( + fontSize: 21.0, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ], + ), + ), + ), + ], + )), + Container( + height: 10.0, + ), + Container( + margin: _gameMargin, + width: _queryData.size.width - _gameMargin.left * 2, + height: _queryData.size.width - _gameMargin.left * 2 + 10, + child: GestureDetector( + onVerticalDragUpdate: (detail) { + if (detail.delta.distance == 0 || _isDragging) { + return; + } + _isDragging = true; + if (detail.delta.direction > 0) { + moveDown(); + } else { + moveUp(); + } + }, + onVerticalDragEnd: (detail) { + _isDragging = false; + }, + onVerticalDragCancel: () { + _isDragging = false; + }, + onHorizontalDragUpdate: (detail) { + if (detail.delta.distance == 0 || _isDragging) { + return; + } + _isDragging = true; + if (detail.delta.direction > 0) { + moveLeft(); + } else { + moveRight(); + } + }, + onHorizontalDragDown: (detail) { + _isDragging = false; + }, + onHorizontalDragCancel: () { + _isDragging = false; + }, + child: Stack( + children: children, + ), + )), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + CupertinoButton( + padding: EdgeInsets.all(5), + onPressed: () { + var arr = []; + if (_game.canMoveDown()) { + arr.add(1); + } + if (_game.canMoveLeft()) { + arr.add(2); + } + if (_game.canMoveRight()) { + arr.add(3); + } + if (_game.canMoveUp()) { + arr.add(4); + } + + arr.shuffle(); + + if (arr.length > 0) { + int num = arr.first; + if (num == 1) { + moveDown(); + } else if (num == 2) { + moveLeft(); + } else if (num == 3) { + moveRight(); + } else if (num == 4) { + moveUp(); + } + } + + setState(() {}); + }, + child: Column( + children: [ + Icon( + Icons.casino_outlined, + color: Color(0xffFF9C76), + ), + Text("Random", style: TextStyle(fontSize: 15, color: Color(0xffFF9C76))), + ], + )), + CupertinoButton( + padding: EdgeInsets.all(5), + onPressed: () { + _game.shuffle(); + setState(() {}); + }, + child: Column( + children: [ + Icon( + Icons.shuffle_rounded, + color: Color(0xffFF9C76), + ), + Text("Shuffle", style: TextStyle(fontSize: 15, color: Color(0xffFF9C76))), + ], + )), + CupertinoButton( + padding: EdgeInsets.all(5), + onPressed: () { + newGame(); + }, + child: Column( + children: [ + Icon( + Icons.refresh_rounded, + color: Color(0xffFF9C76), + ), + Text("Restart", style: TextStyle(fontSize: 15, color: Color(0xffFF9C76))), + ], + )), + ], + ), + // Spacer(), + // if (_isAdLoaded) + // Container( + // margin: EdgeInsets.fromLTRB(20, 0, 20, 20), + // child: AdWidget(ad: _ad), + // height: 50.0, + // ), + ], + ), + ); + } + + Size boardSize() { + assert(_queryData != null); + Size size = _queryData.size; + double width = size.width - _gameMargin.left - _gameMargin.right; + return Size(width, width); + } +} + +class AnimatedCellWidget extends AnimatedWidget { + final BoardCell cell; + final _GameWidgetState state; + AnimatedCellWidget( + {Key? key, required this.cell, required this.state, required Animation animation}) + : super(key: key, listenable: animation); + + @override + Widget build(BuildContext context) { + final Animation animation = listenable as Animation; + double animationValue = animation.value; + Size boardSize = state.boardSize(); + double width = (boardSize.width - 20 - (state.column + 1) * state.cellPadding) / state.column; + var textColor = Colors.black.withOpacity(0.8); + if ([4, 16, 64, 256, 1048].contains(cell.number)) { + textColor = Colors.black.withOpacity(0.8); + } + if (cell.number == 0) { + return Container(); + } else { + return CellBox( + left: (cell.column * width + 10 + state.cellPadding * (cell.column + 1)) + + width / 2 * (1 - animationValue), + top: cell.row * width + + 10 + + state.cellPadding * (cell.row + 1) + + width / 2 * (1 - animationValue), + size: width * animationValue, + color: BoxColors.containsKey(cell.number) + ? BoxColors[cell.number]! + : BoxColors[BoxColors.keys.last]!, + shadowOffset: state.shadowOffset, + text: Text( + cell.number.toString(), + maxLines: 1, + style: TextStyle( + fontSize: getFontSize(animationValue), + fontWeight: FontWeight.w900, + color: textColor, + ), + ), + ); + } + } + + double getFontSize(double animationValue) { + if (cell.number < 16) { + return 40 * animationValue; + } else if (cell.number < 128) { + return 36 * animationValue; + } else if (cell.number < 1024) { + return 32 * animationValue; + } else { + return 28 * animationValue; + } + } +} + +class CellWidget extends StatefulWidget { + final BoardCell cell; + final _GameWidgetState state; + CellWidget({required this.cell, required this.state}); + _CellWidgetState createState() => _CellWidgetState(); +} + +class _CellWidgetState extends State with SingleTickerProviderStateMixin { + late AnimationController controller; + late Animation animation; + + @override + initState() { + super.initState(); + controller = AnimationController( + duration: Duration( + milliseconds: 200, + ), + vsync: this, + ); + animation = new Tween(begin: 0.0, end: 1.0).animate(controller); + } + + dispose() { + controller.dispose(); + super.dispose(); + widget.cell.isNew = false; + } + + @override + Widget build(BuildContext context) { + if (widget.cell.isNew && !widget.cell.isEmpty()) { + controller.reset(); + controller.forward(); + widget.cell.isNew = false; + } else { + controller.animateTo(1.0); + } + return AnimatedCellWidget( + cell: widget.cell, + state: widget.state, + animation: animation, + ); + } +} + +class CellBox extends StatelessWidget { + final double left; + final double top; + final double size; + final Color color; + final double shadowOffset; + Text? text; + CellBox( + {required this.left, + required this.top, + required this.size, + required this.color, + required this.shadowOffset, + required this.text}); + + @override + Widget build(BuildContext context) { + return Positioned( + left: left, + top: top, + child: color != Colors.white.withOpacity(0.1) + ? Container( + width: size, + height: size, + padding: EdgeInsets.symmetric(horizontal: 5), + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.all(Radius.circular(8.0)), + boxShadow: [ + BoxShadow( + color: Colors.white.withOpacity(0.5), + blurRadius: shadowOffset * 2, + offset: Offset(-shadowOffset, -shadowOffset)), + BoxShadow( + color: Colors.black.withOpacity(0.5), + blurRadius: shadowOffset * 2, + offset: Offset(shadowOffset, shadowOffset)), + ], + ), + child: Center( + child: + FittedBox(fit: BoxFit.scaleDown, alignment: Alignment.center, child: text)), + ) + : Container( + width: size, + height: size, + padding: EdgeInsets.symmetric(horizontal: 5), + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.all(Radius.circular(8.0)), + ), + child: Center( + child: + FittedBox(fit: BoxFit.scaleDown, alignment: Alignment.center, child: text)), + ), + ); + } +} diff --git a/lib/game_pause_cover.dart b/lib/game_pause_cover.dart new file mode 100644 index 0000000..e3d086b --- /dev/null +++ b/lib/game_pause_cover.dart @@ -0,0 +1,55 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class GamePauseCoverPage extends StatefulWidget { + GamePauseCoverPage({Key? key, required this.bg}) : super(key: key); + final String bg; + + @override + _GamePauseCoverPageState createState() => _GamePauseCoverPageState(); +} + +class _GamePauseCoverPageState extends State { + @override + Widget build(BuildContext context) { + TextStyle pageTextStyle = TextStyle(color: Colors.white); + + Widget bodyView = Center( + child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ + Container( + child: CupertinoButton( + borderRadius: BorderRadius.circular(30.0), + color: Color(0xffFF9C76), + onPressed: () { + Navigator.pop(context); + }, + child: Text( + "Continue", + style: TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold), + ), + )), + ])); + + // var onDoubleTap = () { + // print("单击退出当前暂停"); + // Navigator.pop(context); + // }; + var onTap = () { + // print("你单击有鸟用,双击啊"); + Navigator.pop(context); + }; + return GestureDetector( + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/image/${widget.bg}.jpg"), + fit: BoxFit.cover, + ), + ), + child: Scaffold( + backgroundColor: Colors.transparent, + body: DefaultTextStyle(child: bodyView, style: pageTextStyle)), + ), + onTap: onTap); + } +} diff --git a/lib/generated/intl/messages_all.dart b/lib/generated/intl/messages_all.dart new file mode 100644 index 0000000..4f9caac --- /dev/null +++ b/lib/generated/intl/messages_all.dart @@ -0,0 +1,71 @@ +// 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. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:implementation_imports, file_names, unnecessary_new +// ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering +// ignore_for_file:argument_type_not_assignable, invalid_assignment +// ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases +// ignore_for_file:comment_references + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; +import 'package:intl/src/intl_helpers.dart'; + +import 'messages_en.dart' as messages_en; +import 'messages_zh.dart' as messages_zh; +import 'messages_zh_HK.dart' as messages_zh_hk; + +typedef Future LibraryLoader(); +Map _deferredLibraries = { + 'en': () => new SynchronousFuture(null), + 'zh': () => new SynchronousFuture(null), + 'zh_HK': () => new SynchronousFuture(null), +}; + +MessageLookupByLibrary? _findExact(String localeName) { + switch (localeName) { + case 'en': + return messages_en.messages; + case 'zh': + return messages_zh.messages; + case 'zh_HK': + return messages_zh_hk.messages; + default: + return null; + } +} + +/// User programs should call this before using [localeName] for messages. +Future initializeMessages(String localeName) { + var availableLocale = Intl.verifiedLocale( + localeName, (locale) => _deferredLibraries[locale] != null, + onFailure: (_) => null); + if (availableLocale == null) { + return new SynchronousFuture(false); + } + var lib = _deferredLibraries[availableLocale]; + lib == null ? new SynchronousFuture(false) : lib(); + initializeInternalMessageLookup(() => new CompositeMessageLookup()); + messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); + return new SynchronousFuture(true); +} + +bool _messagesExistFor(String locale) { + try { + return _findExact(locale) != null; + } catch (e) { + return false; + } +} + +MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { + var actualLocale = + Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); + if (actualLocale == null) return null; + return _findExact(actualLocale); +} diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart new file mode 100644 index 0000000..76481f1 --- /dev/null +++ b/lib/generated/intl/messages_en.dart @@ -0,0 +1,29 @@ +// 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 +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'en'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "Game_Over": MessageLookupByLibrary.simpleMessage("Game Over"), + "High_Score": MessageLookupByLibrary.simpleMessage("High Score"), + "Score": MessageLookupByLibrary.simpleMessage("Score") + }; +} diff --git a/lib/generated/intl/messages_zh.dart b/lib/generated/intl/messages_zh.dart new file mode 100644 index 0000000..d924bca --- /dev/null +++ b/lib/generated/intl/messages_zh.dart @@ -0,0 +1,29 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a zh locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'zh'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "Game_Over": MessageLookupByLibrary.simpleMessage("游戏结束"), + "High_Score": MessageLookupByLibrary.simpleMessage("最高得分"), + "Score": MessageLookupByLibrary.simpleMessage("得分") + }; +} diff --git a/lib/generated/intl/messages_zh_HK.dart b/lib/generated/intl/messages_zh_HK.dart new file mode 100644 index 0000000..ec02246 --- /dev/null +++ b/lib/generated/intl/messages_zh_HK.dart @@ -0,0 +1,29 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a zh_HK locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'zh_HK'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "Game_Over": MessageLookupByLibrary.simpleMessage("遊戲結束"), + "High_Score": MessageLookupByLibrary.simpleMessage("最高得分"), + "Score": MessageLookupByLibrary.simpleMessage("得分") + }; +} diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart new file mode 100644 index 0000000..487a4a4 --- /dev/null +++ b/lib/generated/l10n.dart @@ -0,0 +1,110 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'intl/messages_all.dart'; + +// ************************************************************************** +// Generator: Flutter Intl IDE plugin +// Made by Localizely +// ************************************************************************** + +// ignore_for_file: non_constant_identifier_names, lines_longer_than_80_chars +// ignore_for_file: join_return_with_assignment, prefer_final_in_for_each +// ignore_for_file: avoid_redundant_argument_values, avoid_escaping_inner_quotes + +class S { + S(); + + static S? _current; + + static S get current { + assert(_current != null, + 'No instance of S was loaded. Try to initialize the S delegate before accessing S.current.'); + return _current!; + } + + static const AppLocalizationDelegate delegate = AppLocalizationDelegate(); + + static Future load(Locale locale) { + final name = (locale.countryCode?.isEmpty ?? false) + ? locale.languageCode + : locale.toString(); + final localeName = Intl.canonicalizedLocale(name); + return initializeMessages(localeName).then((_) { + Intl.defaultLocale = localeName; + final instance = S(); + S._current = instance; + + return instance; + }); + } + + static S of(BuildContext context) { + final instance = S.maybeOf(context); + assert(instance != null, + 'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?'); + return instance!; + } + + static S? maybeOf(BuildContext context) { + return Localizations.of(context, S); + } + + /// `Score` + String get Score { + return Intl.message( + 'Score', + name: 'Score', + desc: '', + args: [], + ); + } + + /// `High Score` + String get High_Score { + return Intl.message( + 'High Score', + name: 'High_Score', + desc: '', + args: [], + ); + } + + /// `Game Over` + String get Game_Over { + return Intl.message( + 'Game Over', + name: 'Game_Over', + desc: '', + args: [], + ); + } +} + +class AppLocalizationDelegate extends LocalizationsDelegate { + const AppLocalizationDelegate(); + + List get supportedLocales { + return const [ + Locale.fromSubtags(languageCode: 'en'), + Locale.fromSubtags(languageCode: 'zh'), + Locale.fromSubtags(languageCode: 'zh', countryCode: 'HK'), + ]; + } + + @override + bool isSupported(Locale locale) => _isSupported(locale); + @override + Future load(Locale locale) => S.load(locale); + @override + bool shouldReload(AppLocalizationDelegate old) => false; + + bool _isSupported(Locale locale) { + for (var supportedLocale in supportedLocales) { + if (supportedLocale.languageCode == locale.languageCode) { + return true; + } + } + return false; + } +} diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb new file mode 100644 index 0000000..0156771 --- /dev/null +++ b/lib/l10n/intl_en.arb @@ -0,0 +1,5 @@ +{ + "Score" : "Score", + "High_Score" : "High Score", + "Game_Over" : "Game Over" +} \ No newline at end of file diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb new file mode 100644 index 0000000..eb34c78 --- /dev/null +++ b/lib/l10n/intl_zh.arb @@ -0,0 +1,5 @@ +{ + "Score" : "得分", + "High_Score" : "最高得分", + "Game_Over" : "游戏结束" +} \ No newline at end of file diff --git a/lib/l10n/intl_zh_HK.arb b/lib/l10n/intl_zh_HK.arb new file mode 100644 index 0000000..5bec5cf --- /dev/null +++ b/lib/l10n/intl_zh_HK.arb @@ -0,0 +1,5 @@ +{ + "Score" : "得分", + "High_Score" : "最高得分", + "Game_Over" : "遊戲結束" +} \ No newline at end of file diff --git a/lib/logic.dart b/lib/logic.dart new file mode 100644 index 0000000..720ab05 --- /dev/null +++ b/lib/logic.dart @@ -0,0 +1,270 @@ +import 'dart:math' show Random; + +class Game { + final int row; + final int column; + final int newNum; + int score = 0; + + Game(this.row, this.column, this.newNum); + + late List> _boardCells; + void init() { + _boardCells = >[]; + for (int r = 0; r < row; ++r) { + _boardCells.add([]); + for (int c = 0; c < column; ++c) { + _boardCells[r].add(BoardCell( + row: r, + column: c, + number: 0, + isNew: false, + )); + } + } + score = 0; + resetMergeStatus(); + randomEmptyCell(2); + } + + BoardCell get(int r, int c) { + return _boardCells[r][c]; + } + + void moveLeft() { + if (!canMoveLeft()) { + return; + } + for (int r = 0; r < row; ++r) { + for (int c = 0; c < column; ++c) { + mergeLeft(r, c); + } + } + randomEmptyCell(newNum); + resetMergeStatus(); + } + + void moveRight() { + if (!canMoveRight()) { + return; + } + for (int r = 0; r < row; ++r) { + for (int c = column - 2; c >= 0; --c) { + mergeRight(r, c); + } + } + randomEmptyCell(newNum); + resetMergeStatus(); + } + + void moveUp() { + if (!canMoveUp()) { + return; + } + for (int r = 0; r < row; ++r) { + for (int c = 0; c < column; ++c) { + mergeUp(r, c); + } + } + randomEmptyCell(newNum); + resetMergeStatus(); + } + + void moveDown() { + if (!canMoveDown()) { + return; + } + for (int r = row - 2; r >= 0; --r) { + for (int c = 0; c < column; ++c) { + mergeDown(r, c); + } + } + randomEmptyCell(newNum); + resetMergeStatus(); + } + + void shuffle() { + List arr = []; + + for (int r = 0; r < row; ++r) { + for (int c = 0; c < column; ++c) { + BoardCell newBoardCell = BoardCell( + row: r, column: c, number: _boardCells[r][c].number, isNew: _boardCells[r][c].isNew); + newBoardCell.isMerged = _boardCells[r][c].isMerged; + arr.add(newBoardCell); + } + } + + print(arr.map((e) => e.number)); + + arr.shuffle(); + + print(arr.map((e) => e.number)); + + int i = 0; + for (int r = 0; r < row; ++r) { + for (int c = 0; c < column; ++c) { + _boardCells[r][c].number = arr[i].number; + _boardCells[r][c].isMerged = arr[i].isMerged; + _boardCells[r][c].isNew = arr[i].isNew; + i = i + 1; + } + } + } + + bool canMoveLeft() { + for (int r = 0; r < row; ++r) { + for (int c = 1; c < column; ++c) { + if (canMerge(_boardCells[r][c], _boardCells[r][c - 1])) { + return true; + } + } + } + return false; + } + + bool canMoveRight() { + for (int r = 0; r < row; ++r) { + for (int c = column - 2; c >= 0; --c) { + if (canMerge(_boardCells[r][c], _boardCells[r][c + 1])) { + return true; + } + } + } + return false; + } + + bool canMoveUp() { + for (int r = 1; r < row; ++r) { + for (int c = 0; c < column; ++c) { + if (canMerge(_boardCells[r][c], _boardCells[r - 1][c])) { + return true; + } + } + } + return false; + } + + bool canMoveDown() { + for (int r = row - 2; r >= 0; --r) { + for (int c = 0; c < column; ++c) { + if (canMerge(_boardCells[r][c], _boardCells[r + 1][c])) { + return true; + } + } + } + return false; + } + + void mergeLeft(int r, int c) { + while (c > 0) { + merge(_boardCells[r][c], _boardCells[r][c - 1]); + c--; + } + } + + void mergeRight(int r, int c) { + while (c < column - 1) { + merge(_boardCells[r][c], _boardCells[r][c + 1]); + c++; + } + } + + void mergeUp(int r, int c) { + while (r > 0) { + merge(_boardCells[r][c], _boardCells[r - 1][c]); + r--; + } + } + + void mergeDown(int r, int c) { + while (r < row - 1) { + merge(_boardCells[r][c], _boardCells[r + 1][c]); + r++; + } + } + + bool canMerge(BoardCell a, BoardCell b) { + return !b.isMerged && ((b.isEmpty() && !a.isEmpty()) || (!a.isEmpty() && a == b)); + } + + void merge(BoardCell a, BoardCell b) { + if (!canMerge(a, b)) { + if (!a.isEmpty() && !b.isMerged) { + b.isMerged = true; + } + return; + } + + if (b.isEmpty()) { + b.number = a.number; + a.number = 0; + } else if (a == b) { + b.number = b.number * 2; + a.number = 0; + score += b.number; + b.isMerged = true; + } else { + b.isMerged = true; + } + } + + bool isGameOver() { + return !canMoveLeft() && !canMoveRight() && !canMoveUp() && !canMoveDown(); + } + + void randomEmptyCell(int cnt) { + List emptyCells = []; + _boardCells.forEach((cells) { + emptyCells.addAll(cells.where((cell) { + return cell.isEmpty(); + })); + }); + if (emptyCells.isEmpty) { + return; + } + Random r = Random(); + for (int i = 0; i < cnt && emptyCells.isNotEmpty; i++) { + int index = r.nextInt(emptyCells.length); + emptyCells[index].number = randomCellNum(); + emptyCells[index].isNew = true; + emptyCells.removeAt(index); + } + } + + // 随机单元数字,出现4的概率为1/15 + int randomCellNum() { + final Random r = Random(); + return r.nextInt(15) == 0 ? 4 : 2; + } + + void resetMergeStatus() { + _boardCells.forEach((cells) { + cells.forEach((cell) { + cell.isMerged = false; + }); + }); + } +} + +class BoardCell { + int row, column; + int number = 0; + bool isMerged = false; + bool isNew = false; + BoardCell({required this.row, required this.column, required this.number, required this.isNew}); + + bool isEmpty() { + return number == 0; + } + + @override + int get hashCode { + return number.hashCode; + } + + @override + bool operator ==(other) { + return other is BoardCell && number == other.number; + } +} diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..c61f4a1 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,219 @@ +import 'package:app_tracking_transparency/app_tracking_transparency.dart'; +import 'package:classic_2048/util/ads_manager.dart'; +import 'package:classic_2048/util/in_app_reviewer_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +import 'game_page.dart'; +import 'generated/l10n.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + + Future.delayed(const Duration(seconds: 1), () { + AppTrackingTransparency.requestTrackingAuthorization(); + }); + + MobileAds.instance.initialize(); + + AdsManager.debugPrintID(); + + InAppReviewHelper.checkAndAskForReview(); + + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) { + runApp(new MyApp()); + }); +} + +final BoxColors = { + 2: Color(0xffEEEEEE), + 4: Color(0xffB6B6B6), + 8: Color(0xffAAFFA2), + 16: Color(0xff46EB36), + 32: Color(0xff85BCF9), + 64: Color(0xff2D88EC), + 128: Color(0xffCA7EF9), + 256: Color(0xff9800F7), + 512: Color(0xffFAD17A), + 1024: Color(0xffF9B222), +}; + +final RouteObserver routeObserver = RouteObserver(); + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + final appTitle = '2048'; + return MaterialApp( + title: appTitle, + debugShowCheckedModeBanner: false, + localizationsDelegates: [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + navigatorObservers: [routeObserver], + supportedLocales: S.delegate.supportedLocales, + localeResolutionCallback: (locale, supportLocales) { + print(locale); + // 中文 简繁体处理 + if (locale?.languageCode == 'zh') { + if (locale?.scriptCode == 'Hant') { + return const Locale('zh', 'HK'); //繁体 + } else { + return const Locale('zh', ''); //简体 + } + } + return Locale('en', ''); + }, + home: GameChoose()); + } +} + +class GameChoose extends StatefulWidget { + const GameChoose({Key? key}) : super(key: key); + + @override + _GameChooseState createState() => _GameChooseState(); +} + +class _GameChooseState extends State { + late BannerAd _ad; + + bool _isAdLoaded = false; + late AppLifecycleReactor _appLifecycleReactor; + + final _appOpenAdManager = AppOpenAdManager(); + + @override + void initState() { + super.initState(); + _ad = BannerAd( + adUnitId: AdsManager.bannerAdUnitId, + size: AdSize.banner, + request: AdRequest(), + listener: BannerAdListener( + onAdLoaded: (_) { + setState(() { + _isAdLoaded = true; + }); + }, + onAdFailedToLoad: (ad, error) { + // Releases an ad resource when it fails to load + ad.dispose(); + + print('Ad load failed (code=${error.code} message=${error.message})'); + }, + ), + ); + + _ad.load(); + + _appLifecycleReactor = + AppLifecycleReactor(appOpenAdManager: _appOpenAdManager); + _appLifecycleReactor.listenToAppStateChanges(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color(0xffFAFAFA), + body: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/image/bg.jpg"), + fit: BoxFit.cover, + ), + ), + child: SafeArea( + child: Stack( + children: [ + ListView( + children: [ + Container( + margin: EdgeInsets.only(top: 40, left: 20, right: 20), + child: Center( + child: Text( + "2048", + style: TextStyle( + color: Colors.white, fontSize: 36, fontWeight: FontWeight.bold), + ), + )), + Container( + margin: EdgeInsets.only(top: 40, left: 20, right: 20), + child: Text( + "Choose Game Mode", + style: TextStyle( + fontSize: 24, color: Colors.white, fontWeight: FontWeight.w600), + textAlign: TextAlign.center, + )), + Container( + margin: EdgeInsets.only(top: 10, left: 20, right: 20), + child: Text( + "Row × Column (new cell per move)", + style: TextStyle( + fontSize: 18, color: Colors.white, fontWeight: FontWeight.w400), + textAlign: TextAlign.center, + )), + SizedBox( + height: 40, + ), + _buildLevelButton(context, 4, 1, "bg1"), + _buildLevelButton(context, 5, 1, "bg2"), + _buildLevelButton(context, 5, 2, "bg3"), + _buildLevelButton(context, 6, 2, "bg4"), + _buildLevelButton(context, 6, 3, "bg5"), + SizedBox( + height: 50, + ), + ], + ), + if (_isAdLoaded) + Align( + alignment: Alignment.bottomCenter, + child: Container( + margin: EdgeInsets.fromLTRB(20, 0, 20, 0), + child: AdWidget(ad: _ad), + height: 50.0, + ), + ), + ], + ), + ), + )); + } + + Container _buildLevelButton(BuildContext context, int row, int newNum, String background) { + return Container( + margin: EdgeInsets.only(bottom: 28, left: 40, right: 40), + height: 60, + child: Container( + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => GamePage( + row: row, + newNum: newNum, + bg: background, + ), + ), + ); + }, + child: Text( + "$row × $row ($newNum)", + style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600), + ), + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(Color(0xff373C69)), + shape: MaterialStateProperty.all( + RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)))), + ), + ), + ); + } +} diff --git a/lib/util/ads_manager.dart b/lib/util/ads_manager.dart new file mode 100644 index 0000000..f1e04f2 --- /dev/null +++ b/lib/util/ads_manager.dart @@ -0,0 +1,173 @@ +import 'dart:io'; + +import 'package:classic_2048/secrets.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +class AdsManager { + static bool disableAllAdsForScreenshot = false; + static String bannerAdUnitIdIOS = Secrets.bannerAdUnitIdAndroid; + static String openAdUnitIDIOS = Secrets.openAdUnitIDIOS; + + static String bannerAdUnitIdAndroid = Secrets.bannerAdUnitIdAndroid; + static String openAdUnitIDAndroid = Secrets.openAdUnitIDAndroid; + + static String get bannerAdUnitId { + if (Platform.isAndroid) { + if (kDebugMode) { + if (disableAllAdsForScreenshot) { + return ""; + } else { + return "ca-app-pub-3940256099942544/6300978111"; + } + } else { + // android banner ID + return bannerAdUnitIdAndroid; + } + } else if (Platform.isIOS) { + if (kDebugMode) { + if (disableAllAdsForScreenshot) { + return ""; + } else { + return "ca-app-pub-3940256099942544/2934735716"; + } + } else { + // ios banner ID + return bannerAdUnitIdIOS; + } + } else { + throw new UnsupportedError("Unsupported platform"); + } + } + + static String get openAdUnitID { + if (Platform.isAndroid) { + if (kDebugMode) { + if (disableAllAdsForScreenshot) { + return ""; + } else { + return 'ca-app-pub-3940256099942544/9257395921'; + } + } else { + // android openAd ID + return openAdUnitIDAndroid; + } + } else if (Platform.isIOS) { + if (kDebugMode) { + if (disableAllAdsForScreenshot) { + return ""; + } else { + return 'ca-app-pub-3940256099942544/5662855259'; + } + } else { + // ios openAd ID + return openAdUnitIDIOS; + } + } else { + throw new UnsupportedError("Unsupported platform"); + } + } + + static void debugPrintID() { + print("bannerAdUnitId: ${AdsManager.bannerAdUnitId}"); + // print("openAdUnitID: ${AdsManager.openAdUnitID}"); + } +} + +class AppOpenAdManager { + AppOpenAd? _appOpenAd; + bool _isShowingAd = false; + + /// Maximum duration allowed between loading and showing the ad. + final Duration maxCacheDuration = Duration(hours: 4); + + /// Keep track of load time so we don't show an expired ad. + DateTime? _appOpenLoadTime; + + /// Load an AppOpenAd. + void loadAd() { + AppOpenAd.load( + adUnitId: AdsManager.openAdUnitID, + orientation: AppOpenAd.orientationPortrait, + request: AdRequest(), + adLoadCallback: AppOpenAdLoadCallback( + onAdLoaded: (ad) { + print('$ad loaded'); + _appOpenLoadTime = DateTime.now(); + _appOpenAd = ad; + }, + onAdFailedToLoad: (error) { + print('AppOpenAd failed to load: $error'); + // Handle the error. + }, + ), + ); + } + + /// Whether an ad is available to be shown. + bool get isAdAvailable { + return _appOpenAd != null; + } + + void showAdIfAvailable() { + if (!isAdAvailable) { + print('Tried to show ad before available.'); + loadAd(); + return; + } + if (_isShowingAd) { + print('Tried to show ad while already showing an ad.'); + return; + } + if (DateTime.now().subtract(maxCacheDuration).isAfter(_appOpenLoadTime!)) { + print('Maximum cache duration exceeded. Loading another ad.'); + _appOpenAd!.dispose(); + _appOpenAd = null; + loadAd(); + return; + } + + // Set the fullScreenContentCallback and show the ad. + _appOpenAd!.fullScreenContentCallback = FullScreenContentCallback( + onAdShowedFullScreenContent: (ad) { + _isShowingAd = true; + print('$ad onAdShowedFullScreenContent'); + }, + onAdFailedToShowFullScreenContent: (ad, error) { + print('$ad onAdFailedToShowFullScreenContent: $error'); + _isShowingAd = false; + ad.dispose(); + _appOpenAd = null; + }, + onAdDismissedFullScreenContent: (ad) { + print('$ad onAdDismissedFullScreenContent'); + _isShowingAd = false; + ad.dispose(); + _appOpenAd = null; + loadAd(); + }, + ); + _appOpenAd!.show(); + } +} + +/// Listens for app foreground events and shows app open ads. +class AppLifecycleReactor { + final AppOpenAdManager appOpenAdManager; + + AppLifecycleReactor({required this.appOpenAdManager}); + + void listenToAppStateChanges() { + AppStateEventNotifier.startListening(); + AppStateEventNotifier.appStateStream + .forEach((state) => _onAppStateChanged(state)); + } + + void _onAppStateChanged(AppState appState) { + debugPrint('New AppState state: $appState'); + if (appState == AppState.foreground) { + appOpenAdManager.showAdIfAvailable(); + } + } +} \ No newline at end of file diff --git a/lib/util/in_app_reviewer_helper.dart b/lib/util/in_app_reviewer_helper.dart new file mode 100644 index 0000000..3f8e9ef --- /dev/null +++ b/lib/util/in_app_reviewer_helper.dart @@ -0,0 +1,32 @@ +import 'package:in_app_review/in_app_review.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class InAppReviewHelper { + static String openCount = "openCount"; + static InAppReview inAppReview = InAppReview.instance; + + static Future incrementOpenCount() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + int? count = prefs.getInt(openCount); + if (count != null) { + count += 1; + prefs.setInt(openCount, count); + } else { + prefs.setInt(openCount, 1); + } + } + + static Future checkAndAskForReview() async { + await incrementOpenCount(); + + SharedPreferences prefs = await SharedPreferences.getInstance(); + int? count = prefs.getInt(openCount); + + print("App open count: $count"); + if (count == 3 || count == 15 || count == 100) { + if (await inAppReview.isAvailable()) { + inAppReview.requestReview(); + } + } + } +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..650f7c2 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,551 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + app_tracking_transparency: + dependency: "direct main" + description: + name: app_tracking_transparency + sha256: "881681b0e6ae560689ec31dc2bfbd61d27fb3056be972694e7b5c765af10836e" + url: "https://pub.dev" + source: hosted + version: "2.0.2+1" + archive: + dependency: transitive + description: + name: archive + sha256: "29fa72e85814672ab1e4d8b36f21cfadd34b16ce2c5c35e86a00df560e9b7940" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + args: + dependency: transitive + description: + name: args + sha256: "0bd9a99b6eb96f07af141f0eb53eace8983e8e5aa5de59777aca31684680ef22" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + async: + dependency: transitive + description: + name: async + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" + source: hosted + version: "2.10.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" + source: hosted + version: "1.2.1" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" + source: hosted + version: "1.17.0" + crypto: + dependency: transitive + description: + name: crypto + sha256: cf75650c66c0316274e21d7c43d3dea246273af5955bd94e8184837cd577575c + url: "https://pub.dev" + source: hosted + version: "3.0.1" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + url: "https://pub.dev" + source: hosted + version: "1.0.6" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "35d0f481d939de0d640b3db9a7aa36a52cd22054a798a73b4f50bdad5ce12678" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + file: + dependency: "direct main" + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: e4d29b76a94cc439c3cb1d8946020bd478e50480a72a256ed6861dae91897962 + url: "https://pub.dev" + source: hosted + version: "0.9.2" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_native_splash: + dependency: "direct dev" + description: + name: flutter_native_splash + sha256: "20349c72751475531d72a3b6b020a3c9a600754b250f03fbbdc649d26671a503" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + flutter_neumorphic: + dependency: "direct main" + description: + name: flutter_neumorphic + sha256: "02606d937a3ceaa497b8a7c25f3efa95188bf93d77ebf0bd6552e432db4c2ec6" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + sha256: b3ae793108ad2a7e8f2fea91ca5bb2ba7ef03621c4d9ed7a92fe3391da64c000 + url: "https://pub.dev" + source: hosted + version: "8.0.8" + google_mobile_ads: + dependency: "direct main" + description: + name: google_mobile_ads + sha256: "117b21e50b2c489ae675f7ddc97fc5e987355a5307128aece3de3ba3f8a01272" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + image: + dependency: transitive + description: + name: image + sha256: "67994d6579afa180c5eb463afa7ad211caab3535e5cbf630f8bd06a098030f54" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + in_app_review: + dependency: "direct main" + description: + name: in_app_review + sha256: "99869244d09adc76af16bf8fd731dd13cef58ecafd5917847589c49f378cbb30" + url: "https://pub.dev" + source: hosted + version: "2.0.9" + in_app_review_platform_interface: + dependency: transitive + description: + name: in_app_review_platform_interface + sha256: fed2c755f2125caa9ae10495a3c163aa7fab5af3585a9c62ef4a6920c5b45f10 + url: "https://pub.dev" + source: hosted + version: "2.0.5" + intl: + dependency: "direct main" + description: + name: intl + sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + url: "https://pub.dev" + source: hosted + version: "0.17.0" + js: + dependency: transitive + description: + name: js + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" + source: hosted + version: "0.6.5" + launch_review: + dependency: "direct main" + description: + name: launch_review + sha256: "04cdaf752033cefd53bc0fa9c22105801ef53791a93d8b6cdd00fcb3c1c1604b" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" + source: hosted + version: "0.12.13" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + meta: + dependency: transitive + description: + name: meta + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" + source: hosted + version: "1.8.0" + open_store: + dependency: "direct main" + description: + name: open_store + sha256: "89996283b040f0a86ee46b7bec0f354779e128fa47b56eb5f98c9159da2d7694" + url: "https://pub.dev" + source: hosted + version: "0.2.4" + path: + dependency: transitive + description: + name: path + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" + source: hosted + version: "1.8.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: "1e109f4df28bd95eab71e323008b53d19c4d633bc1ab05b577518773474e9621" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "3dc0d51b07f85fec3746d9f4e8d31c73bb173cafa2e763f03f8df2e8d1878882" + url: "https://pub.dev" + source: hosted + version: "2.0.3" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "366ad4e3541ea707f859e7148d4d5aba67d589d7936cee04a05c464a277eeb27" + url: "https://pub.dev" + source: hosted + version: "2.0.5" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "1a914995d4ef10c94ff183528c120d35ed43b5eaa8713fc6766a9be4570782e2" + url: "https://pub.dev" + source: hosted + version: "4.4.0" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "075f927ebbab4262ace8d0b283929ac5410c0ac4e7fc123c76429564facfb757" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "1cd0c3c0be0826eb52362ab018a81eed13b616ad9a52548c6ceb1bb349e6b6eb" + url: "https://pub.dev" + source: hosted + version: "2.0.13" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: bc236594233d10b7668dd90414fe0e09d906115aaa1dfe269e478e5f2af532a6 + url: "https://pub.dev" + source: hosted + version: "2.0.11" + shared_preferences_ios: + dependency: transitive + description: + name: shared_preferences_ios + sha256: "32e5384a16c2ef13e4dbac73c735d91276b06e33590a3d1fe7392b6bd9d5002d" + url: "https://pub.dev" + source: hosted + version: "2.0.10" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: ac361c65c4cf342dfc0a8b9e45eab66b9b3ad6eaff9785850d4ec0cf6b474422 + url: "https://pub.dev" + source: hosted + version: "2.1.0" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + sha256: f063907c3f678de8daa033d234b7c9e420df5fe3d499a97bfb82cc30cf171496 + url: "https://pub.dev" + source: hosted + version: "2.0.3" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "992f0fdc46d0a3c0ac2e5859f2de0e577bbe51f78a77ee8f357cbe626a2ad32d" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "09da0185028a227d51721cade7a3cbd5cc5f163a19593266f2acba87f729bf9c" + url: "https://pub.dev" + source: hosted + version: "2.0.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: ae68cf0df0910e38c95522dbd8a6082ce9715053c369750c5709d17de81d032e + url: "https://pub.dev" + source: hosted + version: "2.1.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" + source: hosted + version: "0.4.16" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: "79f78ddad839ee3aae3ec7c01eb4575faf0d5c860f8e5223bc9f9c17f7f03cef" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3 + url: "https://pub.dev" + source: hosted + version: "6.1.11" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: b693e6698f7e6985710d67a050e3acbdda3b9cfc4b43b9f1c40cdbe42c705b92 + url: "https://pub.dev" + source: hosted + version: "6.0.15" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: e51a93f0da65733beb69fdbc43cea524d86ed8e524479e9faefc9304cec34a57 + url: "https://pub.dev" + source: hosted + version: "6.0.15" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: c3ec89d52305ec647cf037eafe2be8d2f1149b5723d1f2ec716fc3d58469de5d + url: "https://pub.dev" + source: hosted + version: "3.0.0" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: c028c7f80fdb99cf48b94c471c0f8b9b855a188f4865df76e2a7663ae640e9d2 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "88de707cba8e0c1c678ed79274298c4737f7f24addd12e786fbf0597de085850" + url: "https://pub.dev" + source: hosted + version: "2.0.6" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: aa14bdb9265fa22416fc387b33e44eb37fd38768bf465fafcec73d283f3457b1 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + win32: + dependency: transitive + description: + name: win32 + sha256: cde1e6d546d8cfd0b3c72bc6f29d980fa629d1cb107f38e2a039ca5d10d79e41 + url: "https://pub.dev" + source: hosted + version: "2.4.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "060b6e1c891d956f72b5ac9463466c37cce3fa962a921532fc001e86fe93438e" + url: "https://pub.dev" + source: hosted + version: "0.2.0+1" + xml: + dependency: transitive + description: + name: xml + sha256: baa23bcba1ba4ce4b22c0c7a1d9c861e7015cb5169512676da0b85138e72840c + url: "https://pub.dev" + source: hosted + version: "5.3.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: "3cee79b1715110341012d27756d9bae38e650588acd38d3f3c610822e1337ace" + url: "https://pub.dev" + source: hosted + version: "3.1.0" +sdks: + dart: ">=2.19.0 <3.0.0" + flutter: ">=3.7.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..742ed0c --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,115 @@ +name: classic_2048 +description: A new Flutter application. + +# 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 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.3+13 + +environment: + sdk: ">=2.12.0 <3.0.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 + flutter_localizations: + sdk: flutter + + fluttertoast: ^8.0.8 + file: ^6.1.3 + # common +# share: ^2.0.4 +# device_info: ^2.0.3 + open_store: ^0.2.4 +# package_info_plus: ^1.3.0 + url_launcher: ^6.0.17 + launch_review: ^3.0.1 + in_app_review: ^2.0.9 + shared_preferences: ^2.0.9 + google_mobile_ads: ^1.1.0 + intl: ^0.17.0 + app_tracking_transparency: ^2.0.2+1 + flutter_neumorphic: ^3.2.0 + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.5 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_native_splash: ^1.3.1 + flutter_launcher_icons: "^0.9.2" + +flutter_icons: + android: "launcher_icon" + ios: true + image_path: "assets/app_icon.png" + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^1.0.0 + +# 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: + - assets/image/ + # - 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 +flutter_intl: + enabled: true