From da23243d12f9c45a4adc5768c7a6f6d9dd63eaec Mon Sep 17 00:00:00 2001 From: Sagnik Sahoo Date: Thu, 2 Oct 2025 18:44:03 +0530 Subject: [PATCH 1/2] adding a sample app showcasing the usage of the cloudinary flutter sdk --- example/memories/.gitignore | 48 ++ example/memories/.metadata | 33 + example/memories/README.md | 105 +++ example/memories/analysis_options.yaml | 28 + example/memories/android/.gitignore | 14 + example/memories/android/app/build.gradle.kts | 44 ++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 45 ++ .../com/momories/memories/MainActivity.kt | 5 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + example/memories/android/build.gradle.kts | 21 + example/memories/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 5 + example/memories/android/settings.gradle.kts | 25 + example/memories/ios/.gitignore | 34 + .../ios/Flutter/AppFrameworkInfo.plist | 26 + example/memories/ios/Flutter/Debug.xcconfig | 1 + example/memories/ios/Flutter/Release.xcconfig | 1 + .../ios/Runner.xcodeproj/project.pbxproj | 616 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 101 +++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + example/memories/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 ++++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 295 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 450 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 282 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 462 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 704 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 586 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 1674 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 762 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 1226 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 1418 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 ++ .../ios/Runner/Base.lproj/Main.storyboard | 26 + example/memories/ios/Runner/Info.plist | 49 ++ .../ios/Runner/Runner-Bridging-Header.h | 1 + .../ios/RunnerTests/RunnerTests.swift | 12 + .../lib/config/cloudinary_config.dart | 9 + example/memories/lib/main.dart | 49 ++ example/memories/lib/models/memory.dart | 27 + .../lib/screens/add_memory_screen.dart | 465 +++++++++++++ example/memories/lib/screens/home_screen.dart | 191 ++++++ .../lib/screens/photo_viewer_screen.dart | 264 ++++++++ .../lib/services/cloudinary_service.dart | 192 ++++++ .../lib/services/storage_service.dart | 28 + .../lib/widgets/cloudinary_image.dart | 81 +++ example/memories/lib/widgets/photo_grid.dart | 250 +++++++ example/memories/pubspec.yaml | 57 ++ example/memories/screenshots/add.jpg | Bin 0 -> 28541 bytes example/memories/screenshots/home.jpg | Bin 0 -> 37301 bytes example/memories/screenshots/view.jpg | Bin 0 -> 39559 bytes example/memories/test/widget_test.dart | 30 + 77 files changed, 3206 insertions(+) create mode 100644 example/memories/.gitignore create mode 100644 example/memories/.metadata create mode 100644 example/memories/README.md create mode 100644 example/memories/analysis_options.yaml create mode 100644 example/memories/android/.gitignore create mode 100644 example/memories/android/app/build.gradle.kts create mode 100644 example/memories/android/app/src/debug/AndroidManifest.xml create mode 100644 example/memories/android/app/src/main/AndroidManifest.xml create mode 100644 example/memories/android/app/src/main/kotlin/com/momories/memories/MainActivity.kt create mode 100644 example/memories/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 example/memories/android/app/src/main/res/drawable/launch_background.xml create mode 100644 example/memories/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 example/memories/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 example/memories/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 example/memories/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 example/memories/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 example/memories/android/app/src/main/res/values-night/styles.xml create mode 100644 example/memories/android/app/src/main/res/values/styles.xml create mode 100644 example/memories/android/app/src/profile/AndroidManifest.xml create mode 100644 example/memories/android/build.gradle.kts create mode 100644 example/memories/android/gradle.properties create mode 100644 example/memories/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 example/memories/android/settings.gradle.kts create mode 100644 example/memories/ios/.gitignore create mode 100644 example/memories/ios/Flutter/AppFrameworkInfo.plist create mode 100644 example/memories/ios/Flutter/Debug.xcconfig create mode 100644 example/memories/ios/Flutter/Release.xcconfig create mode 100644 example/memories/ios/Runner.xcodeproj/project.pbxproj create mode 100644 example/memories/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 example/memories/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 example/memories/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 example/memories/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 example/memories/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 example/memories/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 example/memories/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 example/memories/ios/Runner/AppDelegate.swift create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 example/memories/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 example/memories/ios/Runner/Base.lproj/Main.storyboard create mode 100644 example/memories/ios/Runner/Info.plist create mode 100644 example/memories/ios/Runner/Runner-Bridging-Header.h create mode 100644 example/memories/ios/RunnerTests/RunnerTests.swift create mode 100644 example/memories/lib/config/cloudinary_config.dart create mode 100644 example/memories/lib/main.dart create mode 100644 example/memories/lib/models/memory.dart create mode 100644 example/memories/lib/screens/add_memory_screen.dart create mode 100644 example/memories/lib/screens/home_screen.dart create mode 100644 example/memories/lib/screens/photo_viewer_screen.dart create mode 100644 example/memories/lib/services/cloudinary_service.dart create mode 100644 example/memories/lib/services/storage_service.dart create mode 100644 example/memories/lib/widgets/cloudinary_image.dart create mode 100644 example/memories/lib/widgets/photo_grid.dart create mode 100644 example/memories/pubspec.yaml create mode 100644 example/memories/screenshots/add.jpg create mode 100644 example/memories/screenshots/home.jpg create mode 100644 example/memories/screenshots/view.jpg create mode 100644 example/memories/test/widget_test.dart diff --git a/example/memories/.gitignore b/example/memories/.gitignore new file mode 100644 index 0000000..954dde9 --- /dev/null +++ b/example/memories/.gitignore @@ -0,0 +1,48 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# 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 + +# Environment variable files +.env diff --git a/example/memories/.metadata b/example/memories/.metadata new file mode 100644 index 0000000..9876868 --- /dev/null +++ b/example/memories/.metadata @@ -0,0 +1,33 @@ +# 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: "6fba2447e95c451518584c35e25f5433f14d888c" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 6fba2447e95c451518584c35e25f5433f14d888c + base_revision: 6fba2447e95c451518584c35e25f5433f14d888c + - platform: android + create_revision: 6fba2447e95c451518584c35e25f5433f14d888c + base_revision: 6fba2447e95c451518584c35e25f5433f14d888c + - platform: ios + create_revision: 6fba2447e95c451518584c35e25f5433f14d888c + base_revision: 6fba2447e95c451518584c35e25f5433f14d888c + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/example/memories/README.md b/example/memories/README.md new file mode 100644 index 0000000..dfe063a --- /dev/null +++ b/example/memories/README.md @@ -0,0 +1,105 @@ +# Memories App + +A beautiful photo memories app built with Flutter, showcasing Cloudinary SDK integration for cloud-based image storage and management. + +## Features + +- 📸 Select multiple photos from gallery +- ☁️ Cloud storage with Cloudinary +- 🖼️ Optimized image delivery and transformations +- 📝 Create named memory collections +- 💾 Persistent data storage +- 📅 Automatic date tracking for each memory +- 🗑️ Delete memories and cloud images +- 🌐 Seamless image upload and retrieval +- 🔒 Secure image storage with environment variables + +## Cloudinary Integration + +This app demonstrates real-world usage of the Cloudinary SDK for Flutter: + +- **Image Upload**: Upload photos directly to Cloudinary cloud storage +- **Optimized Delivery**: Automatic image optimization and responsive delivery +- **Image Transformations**: Support for on-the-fly image transformations +- **Secure Configuration**: Environment-based API credentials management +- **Cloud Management**: Delete images from cloud storage when memories are removed + +## Screenshots + +Place screenshots under `assets/screenshots/` in the project root. Example files: + + +Preview: + +| ![Home screen](screenshots/home.jpg) | ![Add memory](screenshots/add.jpg) | ![Photo viewer](screenshots/view.jpg) | +|:---:|:---:|:---:| +| Home screen | Add memory | Photo viewer | + +Recommended: 1080×1920 PNG or JPEG, optimized for mobile. + +## Environment Setup + +1. Create a `.env` file in the project root: + +```env +CLOUDINARY_CLOUD_NAME=your_cloud_name +CLOUDINARY_API_KEY=your_api_key +CLOUDINARY_API_SECRET=your_api_secret +CLOUDINARY_UPLOAD_PRESET=your_upload_preset +``` + +2. Add `.env` to your `.gitignore` to keep credentials secure + +3. Get your Cloudinary credentials from [Cloudinary Dashboard](https://cloudinary.com/console) + +## Platform Setup + +### Android +Add to `android/app/src/main/AndroidManifest.xml`: + +```xml + + +``` + +### iOS +Add to `ios/Runner/Info.plist`: + +```xml +NSPhotoLibraryUsageDescription +We need access to your photo library to select photos for your memories +NSCameraUsageDescription +We need access to your camera to take photos for your memories +``` + +## How to Use + +1. **Set up Cloudinary**: Configure your `.env` file with Cloudinary credentials +2. **Run the app**: `flutter run` +3. **Add a memory**: Tap the + button +4. **Select photos**: Tap "Add Photos" to pick from gallery (uploads to Cloudinary) +5. **Name your memory**: Enter a title for your collection +6. **Save**: Tap "Save" to create the memory +7. **View photos**: Images are loaded from Cloudinary with optimized delivery +8. **Delete**: Remove memories (also deletes images from Cloudinary cloud) + +## Dependencies + +- `cloudinary_sdk`: Cloudinary SDK for Flutter - cloud image storage +- `flutter_dotenv`: Environment variable management +- `image_picker`: Photo selection from gallery +- `path_provider`: File system access +- `intl`: Date formatting +- `shared_preferences`: Local data persistence +- `http`: Network requests + +## Getting Started + +1. Clone the repository +2. Run `flutter pub get` +3. Set up your `.env` file with Cloudinary credentials +4. Run the app with `flutter run` + +For help with Cloudinary integration, visit the [Cloudinary Documentation](https://cloudinary.com/documentation). + +For Flutter development, view the [Flutter documentation](https://docs.flutter.dev/). diff --git a/example/memories/analysis_options.yaml b/example/memories/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/example/memories/analysis_options.yaml @@ -0,0 +1,28 @@ +# 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.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/example/memories/android/.gitignore b/example/memories/android/.gitignore new file mode 100644 index 0000000..be3943c --- /dev/null +++ b/example/memories/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/example/memories/android/app/build.gradle.kts b/example/memories/android/app/build.gradle.kts new file mode 100644 index 0000000..2fcd4fd --- /dev/null +++ b/example/memories/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.momories.memories" + compileSdk = flutter.compileSdkVersion + ndkVersion = "27.0.12077973" + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.momories.memories" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/example/memories/android/app/src/debug/AndroidManifest.xml b/example/memories/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/example/memories/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/memories/android/app/src/main/AndroidManifest.xml b/example/memories/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..54c32aa --- /dev/null +++ b/example/memories/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/example/memories/android/app/src/main/kotlin/com/momories/memories/MainActivity.kt b/example/memories/android/app/src/main/kotlin/com/momories/memories/MainActivity.kt new file mode 100644 index 0000000..00a3d2d --- /dev/null +++ b/example/memories/android/app/src/main/kotlin/com/momories/memories/MainActivity.kt @@ -0,0 +1,5 @@ +package com.momories.memories + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/example/memories/android/app/src/main/res/drawable-v21/launch_background.xml b/example/memories/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/example/memories/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/memories/android/app/src/main/res/drawable/launch_background.xml b/example/memories/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/example/memories/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/memories/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/memories/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/example/memories/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/memories/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/example/memories/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/memories/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/example/memories/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/memories/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/example/memories/android/app/src/main/res/values-night/styles.xml b/example/memories/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/example/memories/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/memories/android/app/src/main/res/values/styles.xml b/example/memories/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/example/memories/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/memories/android/app/src/profile/AndroidManifest.xml b/example/memories/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/example/memories/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/memories/android/build.gradle.kts b/example/memories/android/build.gradle.kts new file mode 100644 index 0000000..89176ef --- /dev/null +++ b/example/memories/android/build.gradle.kts @@ -0,0 +1,21 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/example/memories/android/gradle.properties b/example/memories/android/gradle.properties new file mode 100644 index 0000000..f018a61 --- /dev/null +++ b/example/memories/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/example/memories/android/gradle/wrapper/gradle-wrapper.properties b/example/memories/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..ac3b479 --- /dev/null +++ b/example/memories/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/example/memories/android/settings.gradle.kts b/example/memories/android/settings.gradle.kts new file mode 100644 index 0000000..ab39a10 --- /dev/null +++ b/example/memories/android/settings.gradle.kts @@ -0,0 +1,25 @@ +pluginManagement { + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.7.3" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/example/memories/ios/.gitignore b/example/memories/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/example/memories/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/example/memories/ios/Flutter/AppFrameworkInfo.plist b/example/memories/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..7c56964 --- /dev/null +++ b/example/memories/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 + 12.0 + + diff --git a/example/memories/ios/Flutter/Debug.xcconfig b/example/memories/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/example/memories/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/example/memories/ios/Flutter/Release.xcconfig b/example/memories/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/example/memories/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/example/memories/ios/Runner.xcodeproj/project.pbxproj b/example/memories/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..85e6aeb --- /dev/null +++ b/example/memories/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,616 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.momories.memories; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.momories.memories.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.momories.memories.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.momories.memories.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.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)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.momories.memories; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.momories.memories; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/example/memories/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/memories/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/example/memories/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/example/memories/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/memories/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/memories/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/memories/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/memories/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/memories/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/memories/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/memories/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..e3773d4 --- /dev/null +++ b/example/memories/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/memories/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/memories/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/example/memories/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/example/memories/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/memories/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/memories/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/memories/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/memories/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/memories/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/memories/ios/Runner/AppDelegate.swift b/example/memories/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..6266644 --- /dev/null +++ b/example/memories/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/example/memories/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/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..797d452e458972bab9d994556c8305db4c827017 GIT binary patch literal 406 zcmV;H0crk;P))>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed2d933e1120817fe9182483a228007b18ab6ae GIT binary patch literal 450 zcmV;z0X_bSP)iGWQ_5NJQ_~rNh*z)}eT%KUb z`7gNk0#AwF^#0T0?hIa^`~Ck;!}#m+_uT050aTR(J!bU#|IzRL%^UsMS#KsYnTF*!YeDOytlP4VhV?b} z%rz_<=#CPc)tU1MZTq~*2=8~iZ!lSa<{9b@2Jl;?IEV8)=fG217*|@)CCYgFze-x? zIFODUIA>nWKpE+bn~n7;-89sa>#DR>TSlqWk*!2hSN6D~Qb#VqbP~4Fk&m`@1$JGr zXPIdeRE&b2Thd#{MtDK$px*d3-Wx``>!oimf%|A-&-q*6KAH)e$3|6JV%HX{Hig)k suLT-RhftRq8b9;(V=235Wa|I=027H2wCDra;{X5v07*qoM6N<$f;9x^2LJ#7 literal 0 HcmV?d00001 diff --git a/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd7b0099ca80c806f8fe495613e8d6c69460d76 GIT binary patch literal 282 zcmV+#0p(^bcu7P-R4C8Q z&e;xxFbF_Vrezo%_kH*OKhshZ6BFpG-Y1e10`QXJKbND7AMQ&cMj60B5TNObaZxYybcN07*qoM6N<$g3m;S%K!iX literal 0 HcmV?d00001 diff --git a/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fe730945a01f64a61e2235dbe3f45b08f7729182 GIT binary patch literal 462 zcmV;<0WtoGP)-}iV`2<;=$?g5M=KQbZ{F&YRNy7Nn@%_*5{gvDM0aKI4?ESmw z{NnZg)A0R`+4?NF_RZexyVB&^^ZvN!{I28tr{Vje;QNTz`dG&Jz0~Ek&f2;*Z7>B|cg}xYpxEFY+0YrKLF;^Q+-HreN0P{&i zK~zY`?b7ECf-n?@;d<&orQ*Q7KoR%4|C>{W^h6@&01>0SKS`dn{Q}GT%Qj_{PLZ_& zs`MFI#j-(>?bvdZ!8^xTwlY{qA)T4QLbY@j(!YJ7aXJervHy6HaG_2SB`6CC{He}f zHVw(fJWApwPq!6VY7r1w-Fs)@ox~N+q|w~e;JI~C4Vf^@d>Wvj=fl`^u9x9wd9 zR%3*Q+)t%S!MU_`id^@&Y{y7-r98lZX0?YrHlfmwb?#}^1b{8g&KzmkE(L>Z&)179 zp<)v6Y}pRl100G2FL_t(o!|l{-Q-VMg#&MKg7c{O0 z2wJImOS3Gy*Z2Qifdv~JYOp;v+U)a|nLoc7hNH;I$;lzDt$}rkaFw1mYK5_0Q(Sut zvbEloxON7$+HSOgC9Z8ltuC&0OSF!-mXv5caV>#bc3@hBPX@I$58-z}(ZZE!t-aOG zpjNkbau@>yEzH(5Yj4kZiMH32XI!4~gVXNnjAvRx;Sdg^`>2DpUEwoMhTs_st8pKG z(%SHyHdU&v%f36~uERh!bd`!T2dw;z6PrOTQ7Vt*#9F2uHlUVnb#ev_o^fh}Dzmq} zWtlk35}k=?xj28uO|5>>$yXadTUE@@IPpgH`gJ~Ro4>jd1IF|(+IX>8M4Ps{PNvmI zNj4D+XgN83gPt_Gm}`Ybv{;+&yu-C(Grdiahmo~BjG-l&mWM+{e5M1sm&=xduwgM9 z`8OEh`=F3r`^E{n_;%9weN{cf2%7=VzC@cYj+lg>+3|D|_1C@{hcU(DyQG_BvBWe? zvTv``=%b1zrol#=R`JB)>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..502f463a9bc882b461c96aadf492d1729e49e725 GIT binary patch literal 586 zcmV-Q0=4~#P)+}#`wDE{8-2Mebf5<{{PqV{TgVcv*r8?UZ3{-|G?_}T*&y;@cqf{ z{Q*~+qr%%p!1pS*_Uicl#q9lc(D`!D`LN62sNwq{oYw(Wmhk)k<@f$!$@ng~_5)Ru z0Z)trIA5^j{DIW^c+vT2%lW+2<(RtE2wR;4O@)Tm`Xr*?A(qYoM}7i5Yxw>D(&6ou zxz!_Xr~yNF+waPe00049Nkl*;a!v6h%{rlvIH#gW3s8p;bFr=l}mRqpW2h zw=OA%hdyL~z+UHOzl0eKhEr$YYOL-c-%Y<)=j?(bzDweB7{b+%_ypvm_cG{SvM=DK zhv{K@m>#Bw>2W$eUI#iU)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G! zhkE!s;%oku3;IwG3U^2kw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn`0X*2 zy3(k600_CSZj?O$Qu%&$;|TGUJrptR(HzyIx>5E(2r{eA(<6t3e3I0B)7d6s7?Z5J zZ!rtKvA{MiEBm&KFtoifx>5P^Z=vl)95XJn()aS5%ad(s?4-=Tkis9IGu{`Fy8r+H07*qoM6N<$f20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0ec303439225b78712f49115768196d8d76f6790 GIT binary patch literal 862 zcmV-k1EKthP)20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f5fea27c705180eb716271f41b582e76dcbd90 GIT binary patch literal 1674 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 literal 0 HcmV?d00001 diff --git a/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/example/memories/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0467bf12aa4d28f374bb26596605a46dcbb3e7c8 GIT binary patch literal 1418 zcmV;51$Fv~P)q zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&&>|-UCa7_51w+ zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq z^={4hPQv)y=I|4n+?>7Fim=dxt1 z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf` zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_> z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0NEx*{soY=0MZExqA5XHQkqi#4gW3 zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62( zdqY93Zy}v&c4n($Vv!UybR8ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;? zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-< z{s<&cCV_1`^TD^ia9!*mQDq& zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H literal 0 HcmV?d00001 diff --git a/example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/example/memories/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/example/memories/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/example/memories/ios/Runner/Base.lproj/LaunchScreen.storyboard b/example/memories/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/example/memories/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/memories/ios/Runner/Base.lproj/Main.storyboard b/example/memories/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/example/memories/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/memories/ios/Runner/Info.plist b/example/memories/ios/Runner/Info.plist new file mode 100644 index 0000000..71a5142 --- /dev/null +++ b/example/memories/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Memories + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + memories + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/example/memories/ios/Runner/Runner-Bridging-Header.h b/example/memories/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/example/memories/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/example/memories/ios/RunnerTests/RunnerTests.swift b/example/memories/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/example/memories/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/example/memories/lib/config/cloudinary_config.dart b/example/memories/lib/config/cloudinary_config.dart new file mode 100644 index 0000000..22e1f11 --- /dev/null +++ b/example/memories/lib/config/cloudinary_config.dart @@ -0,0 +1,9 @@ +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +class CloudinaryConfig { + static String get cloudName => dotenv.env['CLOUDINARY_CLOUD_NAME'] ?? ''; + static String get apiKey => dotenv.env['CLOUDINARY_API_KEY'] ?? ''; + static String get apiSecret => dotenv.env['CLOUDINARY_API_SECRET'] ?? ''; + static String get uploadPreset => dotenv.env['CLOUDINARY_UPLOAD_PRESET'] ?? ''; +} + diff --git a/example/memories/lib/main.dart b/example/memories/lib/main.dart new file mode 100644 index 0000000..8a7e3ca --- /dev/null +++ b/example/memories/lib/main.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'config/cloudinary_config.dart'; +import 'screens/home_screen.dart'; +import 'services/cloudinary_service.dart'; + +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + await dotenv.load(fileName: ".env"); + + CloudinaryService().initialize( + cloudName: CloudinaryConfig.cloudName, + uploadPreset: CloudinaryConfig.uploadPreset, + apiKey: CloudinaryConfig.apiKey, + apiSecret: CloudinaryConfig.apiSecret, + ); + + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Memories', + debugShowCheckedModeBanner: false, + theme: ThemeData( + useMaterial3: true, + colorScheme: ColorScheme.fromSeed( + seedColor: Colors.deepPurple, + brightness: Brightness.light, + ), + cardTheme: const CardThemeData( + elevation: 2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16)), + ), + ), + floatingActionButtonTheme: const FloatingActionButtonThemeData( + elevation: 3, + shape: CircleBorder(), + ), + ), + home: const HomeScreen(), + ); + } +} diff --git a/example/memories/lib/models/memory.dart b/example/memories/lib/models/memory.dart new file mode 100644 index 0000000..cb5b93a --- /dev/null +++ b/example/memories/lib/models/memory.dart @@ -0,0 +1,27 @@ +class Memory { + final String id; + final String title; + final List imagePaths; + final DateTime createdAt; + + Memory({ + required this.id, + required this.title, + required this.imagePaths, + required this.createdAt, + }); + + Map toJson() => { + 'id': id, + 'title': title, + 'imagePaths': imagePaths, + 'createdAt': createdAt.toIso8601String(), + }; + + factory Memory.fromJson(Map json) => Memory( + id: json['id'], + title: json['title'], + imagePaths: List.from(json['imagePaths']), + createdAt: DateTime.parse(json['createdAt']), + ); +} diff --git a/example/memories/lib/screens/add_memory_screen.dart b/example/memories/lib/screens/add_memory_screen.dart new file mode 100644 index 0000000..0b04b75 --- /dev/null +++ b/example/memories/lib/screens/add_memory_screen.dart @@ -0,0 +1,465 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import '../models/memory.dart'; +import '../services/cloudinary_service.dart'; + +class AddMemoryScreen extends StatefulWidget { + const AddMemoryScreen({super.key}); + + @override + State createState() => _AddMemoryScreenState(); +} + +class _AddMemoryScreenState extends State { + final TextEditingController _titleController = TextEditingController(); + final List _selectedImages = []; + final ImagePicker _picker = ImagePicker(); + final CloudinaryService _cloudinaryService = CloudinaryService(); + static const int _maxPhotos = 6; + bool _isUploading = false; + int _uploadProgress = 0; + int _totalToUpload = 0; + + Future _pickImages() async { + final remainingSlots = _maxPhotos - _selectedImages.length; + if (remainingSlots <= 0) { + _showMaxPhotosDialog(); + return; + } + + final List images = await _picker.pickMultiImage(); + if (images.isNotEmpty) { + setState(() { + _selectedImages.addAll(images.take(remainingSlots)); + }); + + if (images.length > remainingSlots) { + _showMaxPhotosDialog(); + } + } + } + + void _showMaxPhotosDialog() { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Maximum $_maxPhotos photos allowed'), + behavior: SnackBarBehavior.floating, + duration: const Duration(seconds: 2), + ), + ); + } + + void _removeImage(int index) { + setState(() { + _selectedImages.removeAt(index); + }); + } + + Future _saveMemory() async { + if (_titleController.text.isEmpty || _selectedImages.isEmpty) { + return; + } + + setState(() { + _isUploading = true; + _totalToUpload = _selectedImages.length; + _uploadProgress = 0; + }); + + try { + final imageFiles = _selectedImages.map((img) => File(img.path)).toList(); + + final uploadedUrls = await _cloudinaryService.uploadMultipleImages( + imageFiles, + onProgress: (current, total) { + setState(() { + _uploadProgress = current; + }); + }, + ); + + if (uploadedUrls.isEmpty) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Failed to upload images. Please try again.'), + backgroundColor: Colors.red, + ), + ); + } + setState(() { + _isUploading = false; + }); + return; + } + + final memory = Memory( + id: DateTime.now().millisecondsSinceEpoch.toString(), + title: _titleController.text, + imagePaths: uploadedUrls, + createdAt: DateTime.now(), + ); + + if (mounted) { + Navigator.pop(context, memory); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Error: $e'), backgroundColor: Colors.red), + ); + } + setState(() { + _isUploading = false; + }); + } + } + + @override + void dispose() { + _titleController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final hasImages = _selectedImages.isNotEmpty; + final canSave = + _titleController.text.isNotEmpty && hasImages && !_isUploading; + + return Scaffold( + backgroundColor: theme.colorScheme.surface, + appBar: AppBar( + backgroundColor: Colors.transparent, + elevation: 0, + leading: TextButton( + onPressed: _isUploading ? null : () => Navigator.pop(context), + child: Text( + 'Cancel', + style: TextStyle( + fontSize: 17, + color: _isUploading + ? theme.colorScheme.onSurface.withValues(alpha: 0.3) + : theme.colorScheme.primary, + ), + ), + ), + leadingWidth: 80, + actions: [ + if (_isUploading) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + children: [ + SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + value: _totalToUpload > 0 + ? _uploadProgress / _totalToUpload + : null, + ), + ), + const SizedBox(width: 8), + Text( + 'Uploading $_uploadProgress/$_totalToUpload', + style: TextStyle( + fontSize: 14, + color: theme.colorScheme.onSurface, + ), + ), + ], + ), + ) + else + TextButton( + onPressed: canSave ? _saveMemory : null, + child: Text( + 'Done', + style: TextStyle( + fontSize: 17, + fontWeight: FontWeight.w600, + color: canSave + ? theme.colorScheme.primary + : theme.colorScheme.onSurface.withValues(alpha: 0.3), + ), + ), + ), + const SizedBox(width: 8), + ], + ), + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(20, 0, 20, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextField( + controller: _titleController, + decoration: const InputDecoration( + hintText: 'New Memory', + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + ), + style: const TextStyle( + fontSize: 34, + fontWeight: FontWeight.bold, + ), + maxLines: 1, + textCapitalization: TextCapitalization.words, + onChanged: (value) => setState(() {}), + ), + if (hasImages) + Padding( + padding: const EdgeInsets.only(top: 4), + child: Text( + '${_selectedImages.length} of $_maxPhotos photos', + style: TextStyle( + fontSize: 15, + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ), + ], + ), + ), + + const SizedBox(height: 32), + + if (hasImages) ...[ + const SizedBox(height: 20), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: _buildPhotoThumbnails(), + ), + const SizedBox(height: 20), + ], + + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: GestureDetector( + onTap: _selectedImages.length < _maxPhotos ? _pickImages : null, + child: Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 48), + decoration: BoxDecoration( + color: _selectedImages.length < _maxPhotos + ? theme.colorScheme.surfaceContainerHighest.withValues( + alpha: 0.5, + ) + : theme.colorScheme.surfaceContainerHighest.withValues( + alpha: 0.3, + ), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: theme.colorScheme.outlineVariant.withValues( + alpha: 0.3, + ), + width: 1, + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (_selectedImages.length < _maxPhotos) ...[ + Icon( + Icons.photo_library_outlined, + size: 44, + color: theme.colorScheme.primary.withValues( + alpha: 0.8, + ), + ), + const SizedBox(height: 12), + Text( + hasImages ? 'Add More Photos' : 'Add Photos', + style: TextStyle( + fontSize: 17, + fontWeight: FontWeight.w500, + color: theme.colorScheme.primary, + ), + ), + if (hasImages) + Padding( + padding: const EdgeInsets.only(top: 4), + child: Text( + '${_selectedImages.length} of $_maxPhotos selected', + style: TextStyle( + fontSize: 13, + color: theme.colorScheme.onSurfaceVariant + .withValues(alpha: 0.7), + ), + ), + ), + ] else ...[ + Icon( + Icons.check_circle_rounded, + size: 44, + color: theme.colorScheme.primary.withValues( + alpha: 0.6, + ), + ), + const SizedBox(height: 12), + Text( + 'All Photos Added', + style: TextStyle( + fontSize: 17, + fontWeight: FontWeight.w500, + color: theme.colorScheme.onSurfaceVariant, + ), + ), + Padding( + padding: const EdgeInsets.only(top: 4), + child: Text( + '$_maxPhotos photos maximum', + style: TextStyle( + fontSize: 13, + color: theme.colorScheme.onSurfaceVariant + .withValues(alpha: 0.6), + ), + ), + ), + ], + ], + ), + ), + ), + ), + + const SizedBox(height: 40), + ], + ), + ), + ); + } + + Widget _buildPhotoThumbnails() { + final theme = Theme.of(context); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.collections, + size: 16, + color: theme.colorScheme.onSurfaceVariant, + ), + const SizedBox(width: 6), + Text( + 'Photos', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w600, + color: theme.colorScheme.onSurfaceVariant, + letterSpacing: 0.5, + ), + ), + const Spacer(), + Text( + 'Tap × to remove', + style: TextStyle( + fontSize: 12, + color: theme.colorScheme.onSurfaceVariant.withValues( + alpha: 0.6, + ), + ), + ), + ], + ), + const SizedBox(height: 12), + SizedBox( + height: 90, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: _selectedImages.length, + itemBuilder: (context, index) { + return Padding( + padding: EdgeInsets.only( + right: index < _selectedImages.length - 1 ? 12 : 0, + ), + child: Stack( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(12), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: theme.colorScheme.outlineVariant.withValues( + alpha: 0.3, + ), + width: 1, + ), + borderRadius: BorderRadius.circular(12), + ), + child: Image.file( + File(_selectedImages[index].path), + width: 90, + height: 90, + fit: BoxFit.cover, + ), + ), + ), + Positioned( + top: 6, + right: 6, + child: GestureDetector( + onTap: () => _removeImage(index), + child: Container( + padding: const EdgeInsets.all(5), + decoration: BoxDecoration( + color: Colors.red.shade600, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.3), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: const Icon( + Icons.close_rounded, + size: 16, + color: Colors.white, + ), + ), + ), + ), + Positioned( + bottom: 6, + left: 6, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, + vertical: 3, + ), + decoration: BoxDecoration( + color: Colors.black.withValues(alpha: 0.6), + borderRadius: BorderRadius.circular(4), + ), + child: Text( + '${index + 1}', + style: const TextStyle( + color: Colors.white, + fontSize: 11, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ], + ), + ); + }, + ), + ), + ], + ); + } +} diff --git a/example/memories/lib/screens/home_screen.dart b/example/memories/lib/screens/home_screen.dart new file mode 100644 index 0000000..d12f0cc --- /dev/null +++ b/example/memories/lib/screens/home_screen.dart @@ -0,0 +1,191 @@ +import 'package:flutter/material.dart'; +import '../models/memory.dart'; +import '../services/cloudinary_service.dart'; +import '../services/storage_service.dart'; +import '../widgets/photo_grid.dart'; +import 'add_memory_screen.dart'; +import 'photo_viewer_screen.dart'; + +class HomeScreen extends StatefulWidget { + const HomeScreen({super.key}); + + @override + State createState() => _HomeScreenState(); +} + +class _HomeScreenState extends State { + List memories = []; + final StorageService _storageService = StorageService(); + final CloudinaryService _cloudinaryService = CloudinaryService(); + bool _isLoading = true; + + @override + void initState() { + super.initState(); + _loadMemories(); + } + + Future _loadMemories() async { + final loadedMemories = await _storageService.loadMemories(); + setState(() { + memories = loadedMemories; + _isLoading = false; + }); + } + + Future _saveMemories() async { + await _storageService.saveMemories(memories); + } + + void _addMemory() async { + final result = await Navigator.push( + context, + MaterialPageRoute(builder: (context) => const AddMemoryScreen()), + ); + + if (result != null) { + setState(() { + memories.insert(0, result); + }); + await _saveMemories(); + } + } + + @override + Widget build(BuildContext context) { + if (_isLoading) { + return const Scaffold(body: Center(child: CircularProgressIndicator())); + } + + return Scaffold( + appBar: AppBar( + title: const Text( + 'Memories', + style: TextStyle(fontWeight: FontWeight.bold), + ), + actions: [ + IconButton( + icon: const Icon(Icons.filter_list), + onPressed: () {}, + tooltip: 'Filter', + ), + ], + ), + body: memories.isEmpty + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.photo_library_outlined, + size: 80, + color: Theme.of(context).colorScheme.secondary, + ), + const SizedBox(height: 16), + Text( + 'No Memories Yet', + style: Theme.of(context).textTheme.headlineSmall?.copyWith( + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(height: 8), + Text( + 'Tap + to create your first memory', + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ) + : ListView( + padding: const EdgeInsets.all(16), + children: _buildSectionedMemories(), + ), + floatingActionButton: FloatingActionButton( + onPressed: _addMemory, + tooltip: 'Add Memory', + child: const Icon(Icons.add), + ), + ); + } + + List _buildSectionedMemories() { + // Sort by most recent first + final List sorted = [...memories] + ..sort((a, b) => b.createdAt.compareTo(a.createdAt)); + + // Group by title + final Map> titleToMemories = {}; + for (final m in sorted) { + titleToMemories.putIfAbsent(m.title, () => []).add(m); + } + + final List widgets = []; + titleToMemories.forEach((title, items) { + widgets.add( + Padding( + padding: const EdgeInsets.only(top: 16, bottom: 8), + child: Text( + title, + style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold), + ), + ), + ); + + for (final memory in items) { + widgets.add(_buildMemoryCard(memory)); + } + }); + + return widgets; + } + + Widget _buildMemoryCard(Memory memory) { + return Card( + margin: const EdgeInsets.only(bottom: 12), + clipBehavior: Clip.antiAlias, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + side: BorderSide( + color: Theme.of(context).colorScheme.outlineVariant.withValues(alpha: 0.5), + width: 1, + ), + ), + child: memory.imagePaths.isNotEmpty + ? PhotoGrid( + imagePaths: memory.imagePaths, + onImageTap: (index) => _openPhotoViewer(memory, index), + ) + : const SizedBox.shrink(), + ); + } + + void _openPhotoViewer(Memory memory, int initialIndex) async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => PhotoViewerScreen( + imagePaths: memory.imagePaths, + initialIndex: initialIndex, + onDelete: (index) async { + final imageUrl = memory.imagePaths[index]; + + if (_cloudinaryService.isCloudinaryUrl(imageUrl)) { + await _cloudinaryService.deleteImage(imageUrl); + } + + setState(() { + memory.imagePaths.removeAt(index); + if (memory.imagePaths.isEmpty) { + memories.remove(memory); + } + }); + _saveMemories(); + }, + ), + ), + ); + } +} diff --git a/example/memories/lib/screens/photo_viewer_screen.dart b/example/memories/lib/screens/photo_viewer_screen.dart new file mode 100644 index 0000000..c31ec42 --- /dev/null +++ b/example/memories/lib/screens/photo_viewer_screen.dart @@ -0,0 +1,264 @@ +import 'package:flutter/material.dart'; +import '../widgets/cloudinary_image.dart'; + +class PhotoViewerScreen extends StatefulWidget { + final List imagePaths; + final int initialIndex; + final Future Function(int index)? onDelete; + + const PhotoViewerScreen({ + super.key, + required this.imagePaths, + this.initialIndex = 0, + this.onDelete, + }); + + @override + State createState() => _PhotoViewerScreenState(); +} + +class _PhotoViewerScreenState extends State { + late PageController _pageController; + late int _currentIndex; + final TransformationController _transformationController = + TransformationController(); + + @override + void initState() { + super.initState(); + _currentIndex = widget.initialIndex; + _pageController = PageController(initialPage: widget.initialIndex); + } + + @override + void dispose() { + _pageController.dispose(); + _transformationController.dispose(); + super.dispose(); + } + + void _resetZoom() { + _transformationController.value = Matrix4.identity(); + } + + void _confirmDelete() { + showDialog( + context: context, + builder: (context) => AlertDialog( + backgroundColor: Colors.grey.shade900, + title: const Text( + 'Delete Photo', + style: TextStyle(color: Colors.white), + ), + content: Text( + 'Are you sure you want to delete this photo?', + style: TextStyle(color: Colors.grey.shade300), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text( + 'Cancel', + style: TextStyle(color: Colors.grey.shade400), + ), + ), + FilledButton( + onPressed: () { + Navigator.pop(context); + _deleteCurrentPhoto(); + }, + style: FilledButton.styleFrom(backgroundColor: Colors.red), + child: const Text('Delete'), + ), + ], + ), + ); + } + + Future _deleteCurrentPhoto() async { + if (widget.onDelete != null) { + await widget.onDelete!(_currentIndex); + + if (widget.imagePaths.length <= 1) { + if (mounted) { + Navigator.pop(context); + } + } else { + if (_currentIndex >= widget.imagePaths.length - 1) { + setState(() { + _currentIndex = widget.imagePaths.length - 2; + }); + _pageController.jumpToPage(_currentIndex); + } + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.black, + extendBody: true, + appBar: AppBar( + backgroundColor: Colors.black.withValues(alpha: 0.5), + elevation: 0, + leading: IconButton( + icon: const Icon(Icons.close), + color: Colors.white, + onPressed: () => Navigator.pop(context), + ), + actions: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(20), + ), + child: Text( + '${_currentIndex + 1} / ${widget.imagePaths.length}', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ], + ), + body: Stack( + children: [ + PageView.builder( + controller: _pageController, + onPageChanged: (index) { + _resetZoom(); + setState(() { + _currentIndex = index; + }); + }, + itemCount: widget.imagePaths.length, + itemBuilder: (context, index) { + return InteractiveViewer( + transformationController: _transformationController, + minScale: 0.5, + maxScale: 5.0, + panEnabled: true, + scaleEnabled: true, + child: Center( + child: Hero( + tag: 'photo_${widget.imagePaths[index]}', + child: CloudinaryImageWidget( + imagePath: widget.imagePaths[index], + fit: BoxFit.contain, + ), + ), + ), + ); + }, + ), + if (widget.imagePaths.length > 1) + Positioned( + bottom: 120, + left: 0, + right: 0, + child: Center( + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + decoration: BoxDecoration( + color: Colors.black.withValues(alpha: 0.6), + borderRadius: BorderRadius.circular(20), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: List.generate( + widget.imagePaths.length > 10 + ? 10 + : widget.imagePaths.length, + (index) { + if (index == 9 && widget.imagePaths.length > 10) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 2), + child: Text( + '...', + style: TextStyle( + color: Colors.white.withValues(alpha: 0.5), + fontSize: 16, + ), + ), + ); + } + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 2), + child: Container( + width: 6, + height: 6, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: _currentIndex == index + ? Colors.white + : Colors.white.withValues(alpha: 0.4), + ), + ), + ); + }, + ), + ), + ), + ), + ), + ], + ), + bottomNavigationBar: Container( + decoration: BoxDecoration( + color: Colors.black.withValues(alpha: 0.5), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.3), + blurRadius: 8, + offset: const Offset(0, -2), + ), + ], + ), + child: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + IconButton( + icon: const Icon(Icons.share_outlined), + color: Colors.white, + onPressed: () {}, + tooltip: 'Share', + ), + IconButton( + icon: const Icon(Icons.zoom_out_map), + color: Colors.white, + onPressed: _resetZoom, + tooltip: 'Reset Zoom', + ), + IconButton( + icon: const Icon(Icons.favorite_border), + color: Colors.white, + onPressed: () {}, + tooltip: 'Favorite', + ), + IconButton( + icon: const Icon(Icons.delete_outline), + color: Colors.white, + onPressed: widget.onDelete != null ? _confirmDelete : null, + tooltip: 'Delete', + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/example/memories/lib/services/cloudinary_service.dart b/example/memories/lib/services/cloudinary_service.dart new file mode 100644 index 0000000..9e91993 --- /dev/null +++ b/example/memories/lib/services/cloudinary_service.dart @@ -0,0 +1,192 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:crypto/crypto.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; + +class CloudinaryService { + static final CloudinaryService _instance = CloudinaryService._internal(); + factory CloudinaryService() => _instance; + CloudinaryService._internal(); + + String? _cloudName; + String? _uploadPreset; + String? _apiKey; + String? _apiSecret; + bool _initialized = false; + + void initialize({ + required String cloudName, + required String uploadPreset, + String? apiKey, + String? apiSecret, + }) { + _cloudName = cloudName; + _uploadPreset = uploadPreset; + _apiKey = apiKey; + _apiSecret = apiSecret; + _initialized = true; + } + + Future uploadImage( + File imageFile, { + Function(double)? onProgress, + }) async { + if (!_initialized || _cloudName == null || _uploadPreset == null) { + throw Exception('Cloudinary not initialized. Call initialize() first.'); + } + + try { + final url = Uri.parse( + 'https://api.cloudinary.com/v1_1/$_cloudName/image/upload', + ); + + final request = http.MultipartRequest('POST', url); + + request.fields['upload_preset'] = _uploadPreset!; + request.fields['folder'] = 'memories'; + + final file = await http.MultipartFile.fromPath('file', imageFile.path); + + request.files.add(file); + + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + + if (response.statusCode == 200) { + final jsonResponse = json.decode(response.body); + return jsonResponse['secure_url'] as String?; + } else { + return null; + } + } catch (e) { + return null; + } + } + + Future> uploadMultipleImages( + List imageFiles, { + Function(int current, int total)? onProgress, + }) async { + final List uploadedUrls = []; + + for (int i = 0; i < imageFiles.length; i++) { + if (onProgress != null) { + onProgress(i + 1, imageFiles.length); + } + + final url = await uploadImage(imageFiles[i]); + if (url != null) { + uploadedUrls.add(url); + } + } + + return uploadedUrls; + } + + Future deleteImage(String imageUrl) async { + if (!_initialized || _cloudName == null) { + throw Exception('Cloudinary not initialized. Call initialize() first.'); + } + + if (_apiKey == null || _apiSecret == null) { + return false; + } + + try { + final publicId = getPublicIdFromUrl(imageUrl); + if (publicId.isEmpty) return false; + + final timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000; + final signature = _generateSignature(publicId, timestamp); + + final url = Uri.parse( + 'https://api.cloudinary.com/v1_1/$_cloudName/image/destroy', + ); + + final response = await http.post( + url, + body: { + 'public_id': publicId, + 'timestamp': timestamp.toString(), + 'api_key': _apiKey!, + 'signature': signature, + }, + ); + + if (response.statusCode == 200) { + final jsonResponse = json.decode(response.body); + return jsonResponse['result'] == 'ok'; + } + return false; + } catch (e) { + return false; + } + } + + String _generateSignature(String publicId, int timestamp) { + final toSign = 'public_id=$publicId×tamp=$timestamp$_apiSecret'; + final bytes = utf8.encode(toSign); + final hash = sha1.convert(bytes); + return hash.toString(); + } + + String getPublicIdFromUrl(String url) { + try { + final uri = Uri.parse(url); + final pathSegments = uri.pathSegments; + + final uploadIndex = pathSegments.indexOf('upload'); + if (uploadIndex != -1 && uploadIndex < pathSegments.length - 1) { + final publicIdWithExtension = pathSegments + .sublist(uploadIndex + 2) + .join('/'); + return publicIdWithExtension.split('.').first; + } + } catch (e) { + debugPrint('Error extracting public ID: $e'); + } + + return ''; + } + + bool isCloudinaryUrl(String path) { + return path.startsWith('http://') || path.startsWith('https://'); + } + + String getOptimizedUrl( + String url, { + int? width, + int? height, + String quality = 'auto', + }) { + if (!isCloudinaryUrl(url)) return url; + + try { + final transformations = []; + + if (width != null) transformations.add('w_$width'); + if (height != null) transformations.add('h_$height'); + transformations.add('q_$quality'); + transformations.add('f_auto'); + + final uri = Uri.parse(url); + final uploadIndex = uri.pathSegments.indexOf('upload'); + + if (uploadIndex != -1) { + final newSegments = List.from(uri.pathSegments); + newSegments.insert(uploadIndex + 1, transformations.join(',')); + + return Uri( + scheme: uri.scheme, + host: uri.host, + pathSegments: newSegments, + ).toString(); + } + } catch (e) { + debugPrint('Error optimizing URL: $e'); + } + + return url; + } +} diff --git a/example/memories/lib/services/storage_service.dart b/example/memories/lib/services/storage_service.dart new file mode 100644 index 0000000..c3aa713 --- /dev/null +++ b/example/memories/lib/services/storage_service.dart @@ -0,0 +1,28 @@ +import 'dart:convert'; +import 'package:shared_preferences/shared_preferences.dart'; +import '../models/memory.dart'; + +class StorageService { + static const String _memoriesKey = 'memories'; + + Future saveMemories(List memories) async { + final prefs = await SharedPreferences.getInstance(); + final memoriesJson = memories + .map((memory) => json.encode(memory.toJson())) + .toList(); + await prefs.setStringList(_memoriesKey, memoriesJson); + } + + Future> loadMemories() async { + final prefs = await SharedPreferences.getInstance(); + final memoriesJson = prefs.getStringList(_memoriesKey) ?? []; + return memoriesJson + .map((jsonStr) => Memory.fromJson(json.decode(jsonStr))) + .toList(); + } + + Future clearMemories() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove(_memoriesKey); + } +} diff --git a/example/memories/lib/widgets/cloudinary_image.dart b/example/memories/lib/widgets/cloudinary_image.dart new file mode 100644 index 0000000..130ecd4 --- /dev/null +++ b/example/memories/lib/widgets/cloudinary_image.dart @@ -0,0 +1,81 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import '../services/cloudinary_service.dart'; + +class CloudinaryImageWidget extends StatelessWidget { + final String imagePath; + final BoxFit fit; + final double? width; + final double? height; + + const CloudinaryImageWidget({ + super.key, + required this.imagePath, + this.fit = BoxFit.cover, + this.width, + this.height, + }); + + @override + Widget build(BuildContext context) { + final cloudinaryService = CloudinaryService(); + final isUrl = cloudinaryService.isCloudinaryUrl(imagePath); + + if (isUrl) { + return CachedNetworkImage( + imageUrl: imagePath, + fit: fit, + width: width, + height: height, + placeholder: (context, url) => Container( + width: width, + height: height, + color: Colors.grey.shade200, + child: const Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ), + ), + ), + errorWidget: (context, url, error) { + return Container( + width: width, + height: height, + color: Colors.grey.shade300, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.error_outline, color: Colors.red, size: 32), + const SizedBox(height: 8), + Text( + 'Failed to load', + style: TextStyle(fontSize: 10, color: Colors.grey.shade600), + ), + ], + ), + ); + }, + fadeInDuration: const Duration(milliseconds: 300), + fadeOutDuration: const Duration(milliseconds: 100), + ); + } else { + return Image.file( + File(imagePath), + width: width, + height: height, + fit: fit, + errorBuilder: (context, error, stackTrace) { + return Container( + width: width, + height: height, + color: Colors.grey.shade300, + child: const Icon(Icons.broken_image, color: Colors.red), + ); + }, + ); + } + } +} diff --git a/example/memories/lib/widgets/photo_grid.dart b/example/memories/lib/widgets/photo_grid.dart new file mode 100644 index 0000000..12b42b2 --- /dev/null +++ b/example/memories/lib/widgets/photo_grid.dart @@ -0,0 +1,250 @@ +import 'package:flutter/material.dart'; +import 'cloudinary_image.dart'; + +class PhotoGrid extends StatelessWidget { + final List imagePaths; + final Function(int index)? onImageTap; + + const PhotoGrid({super.key, required this.imagePaths, this.onImageTap}); + + @override + Widget build(BuildContext context) { + if (imagePaths.isEmpty) return const SizedBox.shrink(); + + final displayPaths = imagePaths.take(6).toList(); + final remaining = imagePaths.length > 6 ? imagePaths.length - 6 : 0; + + switch (displayPaths.length) { + case 1: + return _buildSingleImage(displayPaths[0], 0); + case 2: + return _buildTwoImages(displayPaths); + case 3: + return _buildThreeImages(displayPaths); + case 4: + return _buildFourImages(displayPaths); + case 5: + return _buildFiveImages(displayPaths); + default: + return _buildSixImages(displayPaths, remaining); + } + } + + Widget _buildSingleImage(String path, int index) { + return AspectRatio( + aspectRatio: 16 / 9, + child: _buildTappableImage(path, index, BoxFit.cover), + ); + } + + Widget _buildTwoImages(List paths) { + return SizedBox( + height: 240, + child: Row( + children: [ + Expanded(child: _buildTappableImage(paths[0], 0, BoxFit.cover)), + const SizedBox(width: 4), + Expanded(child: _buildTappableImage(paths[1], 1, BoxFit.cover)), + ], + ), + ); + } + + Widget _buildThreeImages(List paths) { + return SizedBox( + height: 240, + child: Row( + children: [ + Expanded( + flex: 2, + child: _buildTappableImage(paths[0], 0, BoxFit.cover), + ), + const SizedBox(width: 4), + Expanded( + child: Column( + children: [ + Expanded(child: _buildTappableImage(paths[1], 1, BoxFit.cover)), + const SizedBox(height: 4), + Expanded(child: _buildTappableImage(paths[2], 2, BoxFit.cover)), + ], + ), + ), + ], + ), + ); + } + + Widget _buildFourImages(List paths) { + return Column( + children: [ + SizedBox( + height: 180, + child: Row( + children: [ + Expanded( + flex: 2, + child: _buildTappableImage(paths[0], 0, BoxFit.cover), + ), + const SizedBox(width: 4), + Expanded( + child: Column( + children: [ + Expanded( + child: _buildTappableImage(paths[1], 1, BoxFit.cover), + ), + const SizedBox(height: 4), + Expanded( + child: _buildTappableImage(paths[2], 2, BoxFit.cover), + ), + ], + ), + ), + ], + ), + ), + const SizedBox(height: 4), + SizedBox( + height: 100, + child: _buildTappableImage(paths[3], 3, BoxFit.cover), + ), + ], + ); + } + + Widget _buildFiveImages(List paths) { + return Column( + children: [ + SizedBox( + height: 180, + child: Row( + children: [ + Expanded( + flex: 2, + child: _buildTappableImage(paths[0], 0, BoxFit.cover), + ), + const SizedBox(width: 4), + Expanded( + child: Column( + children: [ + Expanded( + child: _buildTappableImage(paths[1], 1, BoxFit.cover), + ), + const SizedBox(height: 4), + Expanded( + child: _buildTappableImage(paths[2], 2, BoxFit.cover), + ), + ], + ), + ), + ], + ), + ), + const SizedBox(height: 4), + SizedBox( + height: 100, + child: Row( + children: [ + Expanded(child: _buildTappableImage(paths[3], 3, BoxFit.cover)), + const SizedBox(width: 4), + Expanded(child: _buildTappableImage(paths[4], 4, BoxFit.cover)), + ], + ), + ), + ], + ); + } + + Widget _buildSixImages(List paths, int remaining) { + return Column( + children: [ + SizedBox( + height: 180, + child: Row( + children: [ + Expanded( + flex: 2, + child: _buildTappableImage(paths[0], 0, BoxFit.cover), + ), + const SizedBox(width: 4), + Expanded( + child: Column( + children: [ + Expanded( + child: _buildTappableImage(paths[1], 1, BoxFit.cover), + ), + const SizedBox(height: 4), + Expanded( + child: _buildTappableImage(paths[2], 2, BoxFit.cover), + ), + ], + ), + ), + ], + ), + ), + const SizedBox(height: 4), + SizedBox( + height: 90, + child: Row( + children: [ + Expanded(child: _buildTappableImage(paths[3], 3, BoxFit.cover)), + const SizedBox(width: 4), + Expanded(child: _buildTappableImage(paths[4], 4, BoxFit.cover)), + const SizedBox(width: 4), + Expanded(child: _buildImageWithOverlay(paths[5], 5, remaining)), + ], + ), + ), + ], + ); + } + + Widget _buildTappableImage(String path, int index, BoxFit fit) { + return GestureDetector( + onTap: onImageTap != null ? () => onImageTap!(index) : null, + child: ClipRRect( + borderRadius: BorderRadius.circular(0), + child: CloudinaryImageWidget( + imagePath: path, + fit: fit, + width: double.infinity, + height: double.infinity, + ), + ), + ); + } + + Widget _buildImageWithOverlay(String path, int index, int remaining) { + return GestureDetector( + onTap: onImageTap != null ? () => onImageTap!(index) : null, + child: ClipRRect( + borderRadius: BorderRadius.circular(0), + child: Stack( + fit: StackFit.expand, + children: [ + CloudinaryImageWidget( + imagePath: path, + fit: BoxFit.cover, + width: double.infinity, + height: double.infinity, + ), + if (remaining > 0) + Container( + color: Colors.black.withValues(alpha: 0.6), + child: Center( + child: Text( + '+$remaining', + style: const TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/example/memories/pubspec.yaml b/example/memories/pubspec.yaml new file mode 100644 index 0000000..a502a9b --- /dev/null +++ b/example/memories/pubspec.yaml @@ -0,0 +1,57 @@ +name: memories +description: "A simple photos app" +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: ^3.8.1 + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + cupertino_icons: ^1.0.8 + image_picker: ^1.0.7 + path_provider: ^2.1.2 + intl: ^0.19.0 + shared_preferences: ^2.2.2 + cloudinary_flutter: ^1.3.0 + cloudinary_url_gen: ^1.8.0 + http: ^1.1.0 + cached_network_image: ^3.3.1 + crypto: ^3.0.3 + flutter_dotenv: ^5.1.0 + +dev_dependencies: + flutter_test: + sdk: flutter + + flutter_lints: ^5.0.0 + +flutter: + + uses-material-design: true + + assets: + - .env \ No newline at end of file diff --git a/example/memories/screenshots/add.jpg b/example/memories/screenshots/add.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b72986399d1f66c2711de3d3e965484de4441366 GIT binary patch literal 28541 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 literal 0 HcmV?d00001 diff --git a/example/memories/test/widget_test.dart b/example/memories/test/widget_test.dart new file mode 100644 index 0000000..5c9ec4f --- /dev/null +++ b/example/memories/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:memories/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} From b595f62922245d2e6db39a05a1f333df85962951 Mon Sep 17 00:00:00 2001 From: Sagnik Sahoo Date: Thu, 2 Oct 2025 18:49:00 +0530 Subject: [PATCH 2/2] Update README to remove screenshot instructions Removed instructions for placing screenshots and updated recommendations. --- example/memories/README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/example/memories/README.md b/example/memories/README.md index dfe063a..bef0cd1 100644 --- a/example/memories/README.md +++ b/example/memories/README.md @@ -26,16 +26,11 @@ This app demonstrates real-world usage of the Cloudinary SDK for Flutter: ## Screenshots -Place screenshots under `assets/screenshots/` in the project root. Example files: - - -Preview: - | ![Home screen](screenshots/home.jpg) | ![Add memory](screenshots/add.jpg) | ![Photo viewer](screenshots/view.jpg) | |:---:|:---:|:---:| | Home screen | Add memory | Photo viewer | -Recommended: 1080×1920 PNG or JPEG, optimized for mobile. + ## Environment Setup