├── scripts
├── flavors
│ ├── dev.json
│ ├── prd.json
│ └── stg.json
├── build_runner.sh
└── run_dev.sh
├── test
└── widget_test.dart
├── ios
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── AppFrameworkInfo.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ └── project.pbxproj
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── .gitignore
└── Podfile
├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ ├── Icon-512.png
│ ├── Icon-maskable-192.png
│ └── Icon-maskable-512.png
├── manifest.json
└── index.html
├── analysis_options.yaml
├── android
├── gradle.properties
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-v21
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── values
│ │ │ │ │ └── styles.xml
│ │ │ │ └── values-night
│ │ │ │ │ └── styles.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── banana_memo
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── .gitignore
├── settings.gradle
└── build.gradle
├── assets
├── images
│ ├── onion-archit.png
│ ├── status-doing.png
│ ├── status-done.png
│ └── status-todo.png
└── fonts
│ ├── NotoSansJP-Bold.otf
│ ├── NotoSansJP-Regular.otf
│ └── OFL.txt
├── lib
├── infrastructure
│ ├── firebase
│ │ ├── firebase_options.dart
│ │ ├── fake_firebase.dart
│ │ └── firebase.dart
│ └── log
│ │ ├── log_level.dart
│ │ ├── log.dart
│ │ ├── fake_logger.dart
│ │ └── logger.dart
├── application
│ ├── types
│ │ ├── flavor.dart
│ │ └── analytics_event.dart
│ ├── interfaces
│ │ ├── logger.dart
│ │ └── firebase.dart
│ ├── state
│ │ ├── memo_list_provider.dart
│ │ ├── editting_memo_notifier.dart
│ │ ├── editting_memo_provider.dart
│ │ └── memo_list_notifier.dart
│ ├── config
│ │ ├── flavor.dart
│ │ └── memo.dart
│ ├── usecases
│ │ ├── delete_memo.dart
│ │ ├── init_app.dart
│ │ ├── add_memo.dart
│ │ └── update_memo.dart
│ └── di
│ │ ├── infrastructure.dart
│ │ └── usecases.dart
├── domain
│ ├── types
│ │ ├── status.dart
│ │ ├── memo.dart
│ │ ├── memo_config.dart
│ │ └── memo.freezed.dart
│ └── features
│ │ ├── memo_validater.dart
│ │ ├── memo_creator.dart
│ │ └── memo_updater.dart
├── main.dart
└── presentation
│ ├── theme
│ ├── images.dart
│ ├── l10n.dart
│ ├── colors.dart
│ ├── sizes.dart
│ └── fonts.dart
│ ├── router
│ ├── page_path.dart
│ ├── app.dart
│ └── go_router.dart
│ ├── widgets
│ ├── status_image.dart
│ ├── gap.dart
│ ├── delete_button.dart
│ ├── status_text.dart
│ ├── status_button.dart
│ ├── browser_adapter.dart
│ ├── text_edit_form.dart
│ ├── add_button.dart
│ ├── save_button.dart
│ └── memo_card.dart
│ ├── pages
│ ├── list.dart
│ └── edit.dart
│ └── dialogs
│ └── warn.dart
├── README.md
├── .vscode
├── tasks.json
├── launch.json
├── settings.json
└── dart.code-snippets
├── pubspec.yaml
├── .gitignore
└── pubspec.lock
/scripts/flavors/dev.json:
--------------------------------------------------------------------------------
1 | {
2 | "flavor": "dev"
3 | }
4 |
--------------------------------------------------------------------------------
/scripts/flavors/prd.json:
--------------------------------------------------------------------------------
1 | {
2 | "flavor": "prd"
3 | }
4 |
--------------------------------------------------------------------------------
/scripts/flavors/stg.json:
--------------------------------------------------------------------------------
1 | {
2 | "flavor": "stg"
3 | }
4 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 |
2 | // アプリ本体のフォルダ構成の例なのでテストは省略
3 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/scripts/build_runner.sh:
--------------------------------------------------------------------------------
1 | flutter pub run build_runner build --delete-conflicting-outputs
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/web/favicon.png
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | linter:
4 | rules:
5 |
--------------------------------------------------------------------------------
/scripts/run_dev.sh:
--------------------------------------------------------------------------------
1 | flutter run --debug -d chrome --dart-define-from-file=scripts/flavors/dev.json
2 |
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/assets/images/onion-archit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/assets/images/onion-archit.png
--------------------------------------------------------------------------------
/assets/images/status-doing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/assets/images/status-doing.png
--------------------------------------------------------------------------------
/assets/images/status-done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/assets/images/status-done.png
--------------------------------------------------------------------------------
/assets/images/status-todo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/assets/images/status-todo.png
--------------------------------------------------------------------------------
/lib/infrastructure/firebase/firebase_options.dart:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Firebaseを使う時はここに firebase_options.dart をおく
4 | *
5 | */
--------------------------------------------------------------------------------
/assets/fonts/NotoSansJP-Bold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/assets/fonts/NotoSansJP-Bold.otf
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/web/icons/Icon-maskable-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/web/icons/Icon-maskable-512.png
--------------------------------------------------------------------------------
/assets/fonts/NotoSansJP-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/assets/fonts/NotoSansJP-Regular.otf
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/lib/application/types/flavor.dart:
--------------------------------------------------------------------------------
1 | /// フレーバー
2 | enum Flavor {
3 | /// 開発
4 | dev,
5 |
6 | /// 試験
7 | stg,
8 |
9 | /// 本番
10 | prd,
11 | }
12 |
--------------------------------------------------------------------------------
/lib/domain/types/status.dart:
--------------------------------------------------------------------------------
1 | /// メモのステータス
2 | enum Status {
3 | /// 予定
4 | todo,
5 |
6 | /// 進行中
7 | doing,
8 |
9 | /// 完了
10 | done,
11 | }
12 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/lib/application/types/analytics_event.dart:
--------------------------------------------------------------------------------
1 | /// 記録しておきたいイベントの種類
2 | enum AnalyticsEvent {
3 | /// 新しいメモを追加した
4 | addNewMemo,
5 |
6 | /// メモを削除した
7 | deleteMemo,
8 | }
9 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/lib/application/interfaces/logger.dart:
--------------------------------------------------------------------------------
1 | abstract class Logger {
2 | void fatal(String msg);
3 | void error(String msg);
4 | void info(String msg);
5 | void debug(String msg);
6 | }
7 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rbdog/flutter_note_folders/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/banana_memo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.my_app
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # お知らせ
2 |
3 | フォルダ構成以外も合わせた実用的で新しいテンプレートアプリを作成中です。
4 |
5 | [新しいテンプレートはこちら](https://github.com/rbdog/templates/tree/main/flutter_mobile_app)
6 |
7 |
8 |
9 | 本リポジトリは動画で説明したフォルダ構成をそのまま残してあります
10 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/lib/application/interfaces/firebase.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/application/types/analytics_event.dart';
2 |
3 | abstract class FirebaseService {
4 | Future init();
5 | Future sendEvent(AnalyticsEvent event);
6 | }
7 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
6 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:hooks_riverpod/hooks_riverpod.dart';
3 | import 'package:my_app/presentation/router/app.dart';
4 |
5 | void main() {
6 | const app = App();
7 | const scope = ProviderScope(child: app);
8 | runApp(scope);
9 | }
10 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/lib/presentation/theme/images.dart:
--------------------------------------------------------------------------------
1 | /// 組み込み画像
2 | enum BrandImage {
3 | statusTodo('status-todo.png'),
4 | statusDoing('status-doing.png'),
5 | statusDone('status-done.png');
6 |
7 | const BrandImage(this.name);
8 |
9 | final String name;
10 | String get path => 'assets/images/$name';
11 | }
12 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | 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.
--------------------------------------------------------------------------------
/lib/application/state/memo_list_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 | import 'package:my_app/domain/types/memo.dart';
3 | import 'package:my_app/application/state/memo_list_notifier.dart';
4 |
5 | /// メモ一覧のプロバイダー
6 | final memoListProvider = StateNotifierProvider>(
7 | (ref) {
8 | return MemoListNotifier([]);
9 | },
10 | );
11 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "open_ios_sim",
6 | "type": "shell",
7 | "command": "open -a Simulator --args -CurrentDeviceUDID ${config:ios.simulator}"
8 | },
9 | {
10 | "label": "open_android_emu",
11 | "type": "shell",
12 | "command": "xxx xxx xxx ${config:android.emulator}"
13 | }
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/lib/domain/types/memo.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/domain/types/status.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 | part 'memo.freezed.dart';
4 |
5 | @freezed
6 | class Memo with _$Memo {
7 | const factory Memo({
8 | /// ID
9 | required String id,
10 |
11 | /// ステータス
12 | required Status status,
13 |
14 | /// 書かれた文字
15 | required String text,
16 | }) = _Memo;
17 | }
18 |
--------------------------------------------------------------------------------
/lib/infrastructure/log/log_level.dart:
--------------------------------------------------------------------------------
1 | /// LogLevel
2 | enum LogLevel {
3 | /// 即時に緊急対応
4 | fatal(60),
5 |
6 | /// 営業時間に最優先で対応
7 | error(50),
8 |
9 | /// 次回リリースまでに対応
10 | warn(40),
11 |
12 | /// 対応不要 大きなイベントと情報を記録
13 | info(30),
14 |
15 | /// 対応不要 小さいイベントと情報を記録
16 | debug(20),
17 |
18 | /// 対応不要 一番小さい情報
19 | trace(10);
20 |
21 | const LogLevel(this.priority);
22 | final int priority;
23 | }
24 |
--------------------------------------------------------------------------------
/lib/domain/features/memo_validater.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/domain/types/memo.dart';
2 |
3 | /// メモが正しいかチェックするクラス
4 | class MemoValidater {
5 | MemoValidater({
6 | required this.maxLength,
7 | });
8 |
9 | /// 最大文字数
10 | final int maxLength;
11 |
12 | /// メモの文字数をチェックする
13 | /// - true: ルールを満たしている OK
14 | /// - false: ルールを満たしていない NG
15 | bool validateLength(Memo memo) {
16 | return memo.text.length <= maxLength;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/domain/types/memo_config.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/domain/types/memo.dart';
2 |
3 | /// メモに関する設定値
4 | class MemoConfig {
5 | MemoConfig({
6 | required this.defaultText,
7 | required this.maxLength,
8 | required this.exampleMemos,
9 | });
10 |
11 | /// はじめからメモに書かれている文字
12 | final String defaultText;
13 |
14 | /// メモに書ける最大文字数
15 | final int maxLength;
16 |
17 | /// サンプルのメモたち
18 | final List exampleMemos;
19 | }
20 |
--------------------------------------------------------------------------------
/lib/infrastructure/firebase/fake_firebase.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/application/types/analytics_event.dart';
2 | import 'package:my_app/application/interfaces/firebase.dart';
3 |
4 | /// 開発環境用のFirebaseサービス
5 | class FakeFirebaseService implements FirebaseService {
6 | @override
7 | Future init() async {
8 | // DO NOTHING
9 | }
10 |
11 | @override
12 | Future sendEvent(AnalyticsEvent event) async {
13 | // DO NOTHING
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/infrastructure/log/log.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/infrastructure/log/log_level.dart';
2 |
3 | /// Log
4 | class Log {
5 | const Log({
6 | required this.createdAt,
7 | required this.level,
8 | required this.tags,
9 | required this.msg,
10 | });
11 |
12 | /// 時刻
13 | final String createdAt;
14 |
15 | /// ログレベル
16 | final LogLevel level;
17 |
18 | /// 本文メッセージ
19 | final String msg;
20 |
21 | /// タグたち
22 | final List tags;
23 | }
24 |
--------------------------------------------------------------------------------
/lib/presentation/router/page_path.dart:
--------------------------------------------------------------------------------
1 | /// 画面ID
2 | enum PageId {
3 | list,
4 | edit,
5 | }
6 |
7 | /// 画面パス
8 | extension PagePath on PageId {
9 | String get path => switch (this) {
10 | PageId.list => '/list',
11 | PageId.edit => '/edit/:id',
12 | };
13 | }
14 |
15 | /// 画面名
16 | extension PageName on PageId {
17 | String get routeName => switch (this) {
18 | PageId.list => 'list',
19 | PageId.edit => 'edit',
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/lib/application/state/editting_memo_notifier.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 | import 'package:my_app/domain/types/memo.dart';
3 |
4 | /// 編集中メモを管理するノティファイヤ
5 | class EdittingMemoNotifier extends StateNotifier {
6 | EdittingMemoNotifier(
7 | /// 初期値
8 | Memo initialMemo,
9 | ) : super(initialMemo);
10 |
11 | /// 現在の状態
12 | Memo get value => state;
13 |
14 | /// 更新
15 | void update(Memo memo) {
16 | state = memo;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/presentation/theme/l10n.dart:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * このアプリの例でL10nパッケージは使わない
4 | * このファイルで代用する
5 | *
6 | */
7 |
8 | /// 文言一覧
9 | class L10n {
10 | static const statusTodo = '予定';
11 | static const statusDoing = '進行中';
12 | static const statusDone = '完了';
13 | static const edit = '編集';
14 | static const createNew = '新規作成';
15 | static const delete = '削除';
16 | static const save = '保存';
17 | static const ok = 'OK';
18 |
19 | static const tooLongTextMesage = '入力文字が長すぎます';
20 | }
21 |
--------------------------------------------------------------------------------
/lib/infrastructure/firebase/firebase.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/application/interfaces/firebase.dart';
2 | import 'package:my_app/application/types/analytics_event.dart';
3 |
4 | /// 本番環境用のFirebaseサービス
5 | class DefaultFirebaseService implements FirebaseService {
6 | @override
7 | Future init() async {
8 | throw Exception('このアプリでFirebaseは使えません');
9 | }
10 |
11 | @override
12 | Future sendEvent(AnalyticsEvent event) async {
13 | throw Exception('このアプリでFirebaseは使えません');
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/application/config/flavor.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/application/types/flavor.dart';
2 |
3 | /// フレーバー
4 | final flavor = _readFlavor();
5 |
6 | /// 設定されたフレーバーを読み取る
7 | Flavor _readFlavor() {
8 | const flavorString = String.fromEnvironment('flavor');
9 | if (flavorString == 'dev') {
10 | return Flavor.dev;
11 | } else if (flavorString == 'stg') {
12 | return Flavor.stg;
13 | } else if (flavorString == 'prd') {
14 | return Flavor.prd;
15 | } else {
16 | // 指定がないときは dev を使う
17 | return Flavor.dev;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/domain/features/memo_creator.dart:
--------------------------------------------------------------------------------
1 | import 'package:uuid/uuid.dart';
2 | import 'package:my_app/domain/types/memo.dart';
3 | import 'package:my_app/domain/types/status.dart';
4 |
5 | /// メモの作成ルールを担当するクラス
6 | class MemoCreater {
7 | MemoCreater({
8 | required this.defaultText,
9 | });
10 |
11 | /// 最初からメモに書かれている文字
12 | final String defaultText;
13 |
14 | /// 新規メモを作成する
15 | Memo createNewMemo() {
16 | /// ランダムな ID を作成
17 | final id = const Uuid().v4();
18 | return Memo(
19 | id: id,
20 | // はじめは 予定 のステータス
21 | status: Status.todo,
22 | text: defaultText,
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/application/state/editting_memo_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 | import 'package:my_app/domain/types/memo.dart';
3 | import 'package:my_app/application/state/editting_memo_notifier.dart';
4 | import 'package:my_app/application/state/memo_list_provider.dart';
5 |
6 | /// 編集中メモのプロバイダー
7 | final edittingMemoProvider =
8 | StateNotifierProvider.family(
9 | (ref, id) {
10 | final list = ref.read(memoListProvider);
11 | final initialState = list.firstWhere(
12 | (memo) => memo.id == id,
13 | );
14 | return EdittingMemoNotifier(initialState);
15 | },
16 | );
17 |
--------------------------------------------------------------------------------
/lib/presentation/theme/colors.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// ブランドカラー
4 | class BrandColor {
5 | static const bananaYellow = Color(0xFFF4B400);
6 | static const grey = Color(0xFFAAAAAA);
7 | static const lightGrey = Color(0xFFEEEEEE);
8 | static const darkGrey = Color(0xFF777777);
9 |
10 | static const white = Colors.white;
11 | static const black = Colors.black;
12 |
13 | static const warnYellow = Colors.yellow;
14 | static const dangerRed = Color(0xFFFC3D39);
15 | static const safeGreen = Color(0xFF53D769);
16 | static const enabledBlue = Color(0xFF147EFB);
17 | static const disabledGrey = Colors.grey;
18 | }
19 |
--------------------------------------------------------------------------------
/lib/domain/features/memo_updater.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/domain/types/memo.dart';
2 | import 'package:my_app/domain/types/status.dart';
3 |
4 | /// メモの更新ルールを担当するクラス
5 | class MemoUpdater {
6 | /// ステータスを次に進める
7 | Memo switchStatus(Memo memo) {
8 | final next = switch (memo.status) {
9 | Status.todo => Status.doing, // 予定 => 進行中
10 | Status.doing => Status.done, // 進行中 => 完了
11 | Status.done => Status.todo, // 完了 => 予定(戻す)
12 | };
13 | // ステータスを変更
14 | return memo.copyWith(status: next);
15 | }
16 |
17 | /// テキストを変更
18 | Memo updateText(Memo memo, String newText) {
19 | // テキストを変更
20 | return memo.copyWith(text: newText);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/application/config/memo.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/domain/types/memo.dart';
2 | import 'package:my_app/domain/types/status.dart';
3 | import 'package:my_app/domain/types/memo_config.dart';
4 |
5 | /// メモに関する設定値
6 | final memoConfig = MemoConfig(
7 | defaultText: 'バナナを買う',
8 | exampleMemos: [
9 | const Memo(
10 | id: 'xxxx-example-01-xxxx',
11 | status: Status.todo,
12 | text: 'バナナを買う',
13 | ),
14 | const Memo(
15 | id: 'xxxx-example-02-xxxx',
16 | status: Status.doing,
17 | text: 'バナナを食べる',
18 | ),
19 | const Memo(
20 | id: 'xxxx-example-03-xxxx',
21 | status: Status.done,
22 | text: 'バナナを捨てる',
23 | ),
24 | ],
25 | maxLength: 20,
26 | );
27 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/status_image.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:my_app/domain/types/status.dart';
3 | import 'package:my_app/presentation/theme/images.dart';
4 |
5 | /// ステータス画像
6 | class StatusImage extends StatelessWidget {
7 | const StatusImage({
8 | super.key,
9 | required this.status,
10 | });
11 |
12 | /// ステータス
13 | final Status status;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Image.asset(
18 | switch (status) {
19 | Status.todo => BrandImage.statusTodo.path,
20 | Status.doing => BrandImage.statusDoing.path,
21 | Status.done => BrandImage.statusDone.path,
22 | },
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/gap.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | ///
4 | /// 部品の間のスキマ
5 | /// - 横幅は Gap.w(12)
6 | /// - 縦幅は Gap.h(12)
7 | /// - のように使う
8 | ///
9 | class Gap extends StatelessWidget {
10 | const Gap._({
11 | required this.width,
12 | required this.height,
13 | });
14 |
15 | final double width;
16 | final double height;
17 |
18 | /// W
19 | factory Gap.w(double width) {
20 | return Gap._(width: width, height: 0);
21 | }
22 |
23 | /// H
24 | factory Gap.h(double height) {
25 | return Gap._(width: 0, height: height);
26 | }
27 |
28 | @override
29 | Widget build(BuildContext context) {
30 | return SizedBox(width: width, height: height);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.7.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.2.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: my_app
2 | description: A new Flutter project.
3 | publish_to: "none"
4 | version: 1.0.0+1
5 | environment:
6 | sdk: ^3.0.0
7 |
8 | dependencies:
9 | flutter:
10 | sdk: flutter
11 | hooks_riverpod: # riverpod + hooks
12 | flutter_hooks: # flutter + hooks
13 | freezed_annotation:
14 | go_router:
15 | uuid:
16 |
17 | dev_dependencies:
18 | flutter_test:
19 | sdk: flutter
20 | flutter_lints: ^2.0.0
21 | build_runner:
22 | freezed:
23 |
24 | flutter:
25 | uses-material-design: true
26 | assets:
27 | - assets/images/
28 | - assets/fonts/OFL.txt
29 | fonts:
30 | - family: NotoSansJP
31 | fonts:
32 | - asset: assets/fonts/NotoSansJP-Bold.otf
33 | - asset: assets/fonts/NotoSansJP-Regular.otf
34 |
--------------------------------------------------------------------------------
/lib/presentation/theme/sizes.dart:
--------------------------------------------------------------------------------
1 | /// 値の意味を含まないサイズ一覧定義
2 | class RawSize {
3 | static const p1 = 1.0;
4 | static const p4 = 4.0;
5 | static const p8 = 8.0;
6 |
7 | static const p12 = 12.0;
8 | static const p14 = 14.0;
9 | static const p16 = 16.0;
10 | static const p18 = 18.0;
11 | static const p20 = 20.0;
12 | static const p22 = 22.0;
13 | static const p24 = 24.0;
14 |
15 | static const p28 = 28.0;
16 | static const p32 = 32.0;
17 |
18 | static const p40 = 40.0;
19 | static const p60 = 60.0;
20 | static const p90 = 90.0;
21 | static const p120 = 120.0;
22 | static const p150 = 150.0;
23 | static const p200 = 200.0;
24 | static const p250 = 250.0;
25 | static const p300 = 300.0;
26 | static const p400 = 300.0;
27 | static const p600 = 300.0;
28 | }
29 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/delete_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:my_app/presentation/theme/colors.dart';
3 | import 'package:my_app/presentation/theme/fonts.dart';
4 | import 'package:my_app/presentation/theme/l10n.dart';
5 |
6 | /// 削除ボタン
7 | class DeleteButton extends StatelessWidget {
8 | const DeleteButton({
9 | super.key,
10 | required this.onPressed,
11 | });
12 |
13 | /// コールバック
14 | final VoidCallback onPressed;
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return TextButton(
19 | onPressed: onPressed,
20 | child: Text(
21 | L10n.delete,
22 | style: BrandText.bodyS.copyWith(
23 | color: BrandColor.dangerRed,
24 | ),
25 | ),
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/status_text.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:my_app/domain/types/status.dart';
3 | import 'package:my_app/presentation/theme/fonts.dart';
4 | import 'package:my_app/presentation/theme/l10n.dart';
5 |
6 | /// ステータス文字
7 | class StatusText extends StatelessWidget {
8 | const StatusText({
9 | super.key,
10 | required this.status,
11 | this.style = BrandText.titleL,
12 | });
13 |
14 | /// ステータス
15 | final Status status;
16 |
17 | /// 文字スタイル
18 | final TextStyle style;
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | final text = switch (status) {
23 | Status.todo => L10n.statusTodo,
24 | Status.doing => L10n.statusDoing,
25 | Status.done => L10n.statusDone,
26 | };
27 | return Text(text, style: style);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/application/usecases/delete_memo.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/application/state/memo_list_notifier.dart';
2 | import 'package:my_app/application/types/analytics_event.dart';
3 | import 'package:my_app/application/interfaces/firebase.dart';
4 | import 'package:my_app/application/interfaces/logger.dart';
5 |
6 | /// メモを削除する
7 | class DeleteMemoUsecase {
8 | DeleteMemoUsecase({
9 | required this.logger,
10 | required this.listNotifier,
11 | required this.firebase,
12 | });
13 | final Logger logger;
14 | final MemoListNotifier listNotifier;
15 | final FirebaseService firebase;
16 |
17 | /// メモを削除する
18 | Future deleteMemo(String id) async {
19 | logger.debug('DeleteMemoUsecase.deleteMemo()');
20 |
21 | // Firebaseにイベントを報告する
22 | firebase.sendEvent(AnalyticsEvent.deleteMemo);
23 |
24 | // リストから削除して状態を変更
25 | listNotifier.delete(id);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 11.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/application/usecases/init_app.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/application/config/memo.dart';
2 | import 'package:my_app/application/state/memo_list_notifier.dart';
3 | import 'package:my_app/application/interfaces/logger.dart';
4 | import 'package:my_app/application/interfaces/firebase.dart';
5 |
6 | /// アプリの初期準備をする
7 | class InitAppUsecase {
8 | InitAppUsecase({
9 | required this.logger,
10 | required this.firebase,
11 | required this.listNotifier,
12 | });
13 | final Logger logger;
14 | final FirebaseService firebase;
15 | final MemoListNotifier listNotifier;
16 |
17 | /// 一連の流れをまとめて実施する
18 | Future execute() async {
19 | logger.debug('InitAppUsecase.execute()');
20 |
21 | // Firebaseを初期化
22 | await firebase.init();
23 |
24 | // リスト一覧を初期化
25 | // 今回はサンプルデータを使う
26 | final initialList = memoConfig.exampleMemos;
27 | listNotifier.set(initialList);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "my_app",
3 | "short_name": "my_app",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | },
22 | {
23 | "src": "icons/Icon-maskable-192.png",
24 | "sizes": "192x192",
25 | "type": "image/png",
26 | "purpose": "maskable"
27 | },
28 | {
29 | "src": "icons/Icon-maskable-512.png",
30 | "sizes": "512x512",
31 | "type": "image/png",
32 | "purpose": "maskable"
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | **/ios/Flutter/.last_build_id
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 |
35 | # Symbolication related
36 | app.*.symbols
37 |
38 | # Obfuscation related
39 | app.*.map.json
40 |
41 | # Android Studio will place build artifacts here
42 | /android/app/debug
43 | /android/app/profile
44 | /android/app/release
45 |
46 | # Firebase
47 | .firebase/
--------------------------------------------------------------------------------
/lib/application/state/memo_list_notifier.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 | import 'package:my_app/domain/types/memo.dart';
3 |
4 | /// メモ一覧を管理するノティファイヤ
5 | class MemoListNotifier extends StateNotifier> {
6 | MemoListNotifier(
7 | /// 初期値
8 | List initialList,
9 | ) : super(initialList);
10 |
11 | /// 新しい一覧をセットする
12 | void set(List list) {
13 | state = list;
14 | }
15 |
16 | /// リストの一番末尾にメモを追加する
17 | void add(Memo memo) {
18 | state = [...state, memo];
19 | }
20 |
21 | /// 指定されたIDのメモを削除する
22 | void delete(String id) {
23 | final list = List.of(state);
24 | list.removeWhere(
25 | (memo) => memo.id == id,
26 | );
27 | state = list;
28 | }
29 |
30 | /// メモを上書きする
31 | void replace(Memo memo) {
32 | state = state.map((old) {
33 | if (old.id == memo.id) {
34 | return memo;
35 | } else {
36 | return old;
37 | }
38 | }).toList();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/status_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:my_app/domain/types/status.dart';
3 | import 'package:my_app/presentation/theme/sizes.dart';
4 | import 'package:my_app/presentation/theme/colors.dart';
5 | import 'package:my_app/presentation/widgets/status_image.dart';
6 |
7 | /// ステータス切り替えボタン
8 | class StatusButton extends StatelessWidget {
9 | const StatusButton({
10 | super.key,
11 | required this.status,
12 | required this.onPressed,
13 | });
14 |
15 | /// 現在のステータス
16 | final Status status;
17 |
18 | /// コールバック
19 | final VoidCallback onPressed;
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return ElevatedButton(
24 | style: ElevatedButton.styleFrom(
25 | backgroundColor: BrandColor.bananaYellow,
26 | padding: const EdgeInsets.all(RawSize.p8),
27 | ),
28 | onPressed: onPressed,
29 | child: StatusImage(status: status),
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/presentation/router/app.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:hooks_riverpod/hooks_riverpod.dart';
3 | import 'package:my_app/presentation/theme/fonts.dart';
4 | import 'package:my_app/presentation/router/go_router.dart';
5 | import 'package:my_app/presentation/widgets/browser_adapter.dart';
6 |
7 | /// アプリ本体
8 | class App extends ConsumerWidget {
9 | const App({super.key});
10 |
11 | @override
12 | Widget build(BuildContext context, WidgetRef ref) {
13 | final router = ref.watch(goRouterProvider);
14 | return MaterialApp.router(
15 | routerDelegate: router.routerDelegate, // GoRouter
16 | routeInformationParser: router.routeInformationParser, // GoRouter
17 | routeInformationProvider: router.routeInformationProvider, // GoRouter
18 | debugShowCheckedModeBanner: false,
19 | builder: (_, child) {
20 | return BrowserAdapter(child: child);
21 | },
22 | theme: ThemeData(
23 | fontFamily: BrandText.bodyS.fontFamily,
24 | ),
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/presentation/theme/fonts.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:my_app/presentation/theme/sizes.dart';
3 |
4 | /// フォント
5 | class BrandFont {
6 | static const general = 'NotoSansJP';
7 | }
8 |
9 | /// 文字スタイル
10 | class BrandText {
11 | static const titleL = TextStyle(
12 | fontSize: RawSize.p28,
13 | fontFamily: BrandFont.general,
14 | fontWeight: FontWeight.bold,
15 | );
16 | static const titleM = TextStyle(
17 | fontSize: RawSize.p24,
18 | fontFamily: BrandFont.general,
19 | fontWeight: FontWeight.bold,
20 | );
21 | static const titleS = TextStyle(
22 | fontSize: RawSize.p20,
23 | fontFamily: BrandFont.general,
24 | );
25 | static const bodyL = TextStyle(
26 | fontSize: RawSize.p18,
27 | fontFamily: BrandFont.general,
28 | );
29 | static const bodyM = TextStyle(
30 | fontSize: RawSize.p16,
31 | fontFamily: BrandFont.general,
32 | );
33 | static const bodyS = TextStyle(
34 | fontSize: RawSize.p16,
35 | fontFamily: BrandFont.general,
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/browser_adapter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | /// ブラウザでもスマホと同じ比率で表示
5 | class BrowserAdapter extends StatelessWidget {
6 | const BrowserAdapter({
7 | super.key,
8 | required this.child,
9 | });
10 |
11 | final Widget? child;
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | if (kIsWeb) {
16 | return Scaffold(
17 | backgroundColor: Colors.grey,
18 | body: Center(
19 | child: AspectRatio(
20 | // テスト表示なので適当に
21 | aspectRatio: 9.0 / 16.0,
22 | child: Container(
23 | decoration: BoxDecoration(
24 | border: Border.all(
25 | color: Colors.black,
26 | width: 5,
27 | ),
28 | ),
29 | child: child,
30 | ),
31 | ),
32 | ),
33 | );
34 | }
35 | // Web以外のときは何もしない
36 | return child ?? const SizedBox.shrink();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/application/di/infrastructure.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 | import 'package:my_app/application/interfaces/firebase.dart';
3 | import 'package:my_app/application/interfaces/logger.dart';
4 | import 'package:my_app/application/config/flavor.dart';
5 | import 'package:my_app/application/types/flavor.dart';
6 | // DI は特別に外レイヤーをimportする
7 | import 'package:my_app/infrastructure/firebase/fake_firebase.dart';
8 | import 'package:my_app/infrastructure/firebase/firebase.dart';
9 | import 'package:my_app/infrastructure/log/fake_logger.dart';
10 |
11 | /// Firebase
12 | final firebaseProvider = Provider((ref) {
13 | return switch (flavor) {
14 | Flavor.dev => FakeFirebaseService(),
15 | Flavor.stg => FakeFirebaseService(),
16 | Flavor.prd => DefaultFirebaseService(),
17 | };
18 | });
19 |
20 | /// Logger
21 | final loggerProvider = Provider((ref) {
22 | return switch (flavor) {
23 | Flavor.dev => FakeLogger(),
24 | Flavor.stg => FakeLogger(),
25 | Flavor.prd => FakeLogger(),
26 | };
27 | });
28 |
--------------------------------------------------------------------------------
/lib/presentation/router/go_router.dart:
--------------------------------------------------------------------------------
1 | import 'package:go_router/go_router.dart';
2 | import 'package:hooks_riverpod/hooks_riverpod.dart';
3 | import 'package:my_app/presentation/pages/edit.dart';
4 | import 'package:my_app/presentation/pages/list.dart';
5 | import 'package:my_app/presentation/router/page_path.dart';
6 |
7 | /// Provide GoRouter
8 | final goRouterProvider = Provider(
9 | (ref) {
10 | final routes = [
11 | GoRoute(
12 | path: PageId.list.path,
13 | name: PageId.list.routeName,
14 | builder: (context, state) {
15 | return const ListPage();
16 | },
17 | ),
18 | GoRoute(
19 | path: PageId.edit.path,
20 | name: PageId.edit.routeName,
21 | builder: (context, state) {
22 | final id = state.pathParameters['id']!;
23 | return EditPage(memoId: id);
24 | },
25 | ),
26 | ];
27 |
28 | return GoRouter(
29 | initialLocation: PageId.list.path,
30 | debugLogDiagnostics: false,
31 | routes: routes,
32 | );
33 | },
34 | );
35 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/text_edit_form.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:hooks_riverpod/hooks_riverpod.dart';
3 | import 'package:flutter_hooks/flutter_hooks.dart';
4 | import 'package:my_app/presentation/theme/fonts.dart';
5 |
6 | /// 文字編集フォーム
7 | class TextEditForm extends HookConsumerWidget {
8 | const TextEditForm({
9 | super.key,
10 | required this.value,
11 | required this.onChanged,
12 | });
13 |
14 | /// 現在の値
15 | final String value;
16 |
17 | /// コールバック 編集
18 | final void Function(String value) onChanged;
19 |
20 | @override
21 | Widget build(BuildContext context, WidgetRef ref) {
22 | /// Hook コントローラー
23 | final controller = useTextEditingController(text: value);
24 | if (controller.text != value) {
25 | // 外から変更された時は反映する
26 | controller.text = value;
27 | }
28 |
29 | return TextField(
30 | style: BrandText.bodyL,
31 | decoration: const InputDecoration(
32 | border: OutlineInputBorder(),
33 | errorText: null,
34 | ),
35 | onChanged: onChanged,
36 | controller: controller,
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/application/usecases/add_memo.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/domain/features/memo_creator.dart';
2 | import 'package:my_app/application/config/memo.dart';
3 | import 'package:my_app/application/state/memo_list_notifier.dart';
4 | import 'package:my_app/application/types/analytics_event.dart';
5 | import 'package:my_app/application/interfaces/firebase.dart';
6 | import 'package:my_app/application/interfaces/logger.dart';
7 |
8 | /// メモを追加する
9 | class AddMemoUsecase {
10 | AddMemoUsecase({
11 | required this.logger,
12 | required this.listNotifier,
13 | required this.firebase,
14 | });
15 | final Logger logger;
16 | final MemoListNotifier listNotifier;
17 | final FirebaseService firebase;
18 |
19 | /// 新しいメモをリストに追加する
20 | Future addNewMemo() async {
21 | logger.debug('AddMemoUsecase.addNewMemo()');
22 | // Firebaseにイベントを報告する
23 | firebase.sendEvent(AnalyticsEvent.addNewMemo);
24 |
25 | // ドメインを呼んで新しいメモを作成
26 | final creator = MemoCreater(
27 | defaultText: memoConfig.defaultText,
28 | );
29 | final memo = creator.createNewMemo();
30 |
31 | // リストに追加して状態を変更
32 | listNotifier.add(memo);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "dev",
6 | "request": "launch",
7 | "type": "dart",
8 | "program": "lib/main.dart",
9 | "args": [
10 | "--debug",
11 | "-d",
12 | "chrome",
13 | "--dart-define-from-file=scripts/flavors/dev.json"
14 | ]
15 | },
16 | {
17 | "name": "stg",
18 | "request": "launch",
19 | "type": "dart",
20 | "program": "lib/main.dart",
21 | "args": [
22 | "--debug",
23 | "-d",
24 | "chrome",
25 | "--web-hostname",
26 | "localhost",
27 | "--web-port=5000",
28 | "--dart-define-from-file=scripts/flavors/stg.json"
29 | ]
30 | },
31 | {
32 | "name": "prd",
33 | "request": "launch",
34 | "type": "dart",
35 | "program": "lib/main.dart",
36 | "args": [
37 | "--release",
38 | "-d",
39 | "chrome",
40 | "--web-hostname",
41 | "localhost",
42 | "--web-port=5000",
43 | "--dart-define-from-file=scripts/flavors/prd.json"
44 | ]
45 | }
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/add_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:my_app/presentation/theme/colors.dart';
3 | import 'package:my_app/presentation/theme/fonts.dart';
4 | import 'package:my_app/presentation/theme/l10n.dart';
5 | import 'package:my_app/presentation/theme/sizes.dart';
6 | import 'package:my_app/presentation/widgets/gap.dart';
7 |
8 | /// 追加ボタン
9 | class AddButton extends StatelessWidget {
10 | const AddButton({
11 | super.key,
12 | required this.onPressed,
13 | });
14 |
15 | /// コールバック
16 | final VoidCallback onPressed;
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | /// アイコン
21 | const icon = Icon(Icons.add);
22 |
23 | /// 文字
24 | const text = Text(
25 | L10n.createNew,
26 | style: BrandText.bodyL,
27 | );
28 |
29 | /// レイアウト
30 | return FloatingActionButton.extended(
31 | heroTag: null,
32 | backgroundColor: BrandColor.bananaYellow,
33 | onPressed: onPressed,
34 | label: Row(
35 | children: [
36 | icon,
37 | Gap.w(RawSize.p8),
38 | text,
39 | ],
40 | ),
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/save_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:my_app/presentation/theme/colors.dart';
3 | import 'package:my_app/presentation/theme/fonts.dart';
4 | import 'package:my_app/presentation/theme/l10n.dart';
5 | import 'package:my_app/presentation/theme/sizes.dart';
6 | import 'package:my_app/presentation/widgets/gap.dart';
7 |
8 | /// 保存ボタン
9 | class SaveButton extends StatelessWidget {
10 | const SaveButton({
11 | super.key,
12 | required this.onPressed,
13 | });
14 |
15 | /// コールバック
16 | final VoidCallback onPressed;
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | /// アイコン
21 | const icon = Icon(Icons.check);
22 |
23 | /// 文字
24 | const text = Text(
25 | L10n.save,
26 | style: BrandText.bodyL,
27 | );
28 |
29 | /// レイアウト
30 | return FloatingActionButton.extended(
31 | heroTag: null,
32 | backgroundColor: BrandColor.bananaYellow,
33 | onPressed: onPressed,
34 | label: Row(
35 | children: [
36 | icon,
37 | Gap.w(RawSize.p8),
38 | text,
39 | ],
40 | ),
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | // --- 以下 個別のPCで設定 ---
3 | // デバイスのID, Xcodeで確認したものを設定
4 | // "ios.simulator": "XXXX-IOS-SIMULATOR-ID-XXXX"
5 | // "ios.device": "XXXX-IOS-DEVICE-ID-XXXX"
6 | // "android.emulator": "XXXX-ANDROID-EMULATOR-ID-XXXX"
7 | // "android.device": "XXXX-ANDROID-DEVICE-ID-XXXX"
8 | "editor.formatOnSave": true,
9 | "dart.debugExternalPackageLibraries": false,
10 | "dart.debugSdkLibraries": false,
11 | "[dart]": {
12 | "editor.rulers": [0],
13 | "editor.defaultFormatter": "Dart-Code.dart-code"
14 | },
15 | "[json]": {
16 | "editor.defaultFormatter": "esbenp.prettier-vscode"
17 | },
18 | "[jsonc]": {
19 | "editor.defaultFormatter": "esbenp.prettier-vscode"
20 | },
21 | "files.exclude": {
22 | "**/.dart_tool": true,
23 | "**/.metadata": true,
24 | "**/.packages": true,
25 | "**/.flutter-plugins": true,
26 | "**/.flutter-plugins-dependencies": true,
27 | "**/.classpath": true,
28 | "**/.project": true,
29 | "**/.settings": true,
30 | "**/.factorypath": true,
31 | "**/generated_plugin_registrant.dart": true,
32 | "**/**.iml": true,
33 | "**/.idea": true,
34 | "**/.gitattributes": true,
35 | "**/build": true,
36 | "**/pubspec.lock": true,
37 | "**/**.freezed.dart": false,
38 | "**/**.g.dart": false,
39 | "**/LICENSE": true,
40 | "**/.gitignore": true,
41 | "**/.firebase": true,
42 | "**/.github": true,
43 | "**/.firebaserc": false,
44 | "**/firebase.json": false
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '11.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
15 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Banana Memo
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | my_app
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UIViewControllerBasedStatusBarAppearance
45 |
46 | CADisableMinimumFrameDurationOnPhone
47 |
48 | UIApplicationSupportsIndirectInputEvents
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | my_app
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/lib/application/usecases/update_memo.dart:
--------------------------------------------------------------------------------
1 | import 'package:my_app/domain/features/memo_updater.dart';
2 | import 'package:my_app/domain/features/memo_validater.dart';
3 | import 'package:my_app/application/config/memo.dart';
4 | import 'package:my_app/application/state/editting_memo_notifier.dart';
5 | import 'package:my_app/application/state/memo_list_notifier.dart';
6 | import 'package:my_app/application/interfaces/firebase.dart';
7 | import 'package:my_app/application/interfaces/logger.dart';
8 |
9 | /// メモを変更する
10 | class UpdateMemoUsecase {
11 | UpdateMemoUsecase({
12 | required this.logger,
13 | required this.edittingNotifier,
14 | required this.listNotifier,
15 | required this.firebase,
16 | });
17 | final Logger logger;
18 | final EdittingMemoNotifier edittingNotifier;
19 | final MemoListNotifier listNotifier;
20 | final FirebaseService firebase;
21 |
22 | /// ステータスを次に進める
23 | Future editStatus() async {
24 | logger.debug('UpdateMemoUsecase.editStatus()');
25 | // ドメインを呼んでステータスを変更する
26 | final updater = MemoUpdater();
27 | final memo = updater.switchStatus(edittingNotifier.value);
28 | // 編集中のメモの状態を変更する
29 | edittingNotifier.update(memo);
30 | }
31 |
32 | /// メモの内容を編集する
33 | Future editText(String newText) async {
34 | logger.debug('UpdateMemoUsecase.newText()');
35 | // ドメインを呼んでステータスを変更する
36 | final updater = MemoUpdater();
37 | final memo = updater.updateText(
38 | edittingNotifier.value,
39 | newText,
40 | );
41 | // 編集中のメモの状態を変更する
42 | edittingNotifier.update(memo);
43 | }
44 |
45 | /// 編集した内容を保存する
46 | Future save({
47 | required void Function() onValidateFailure,
48 | required void Function() onSuccess,
49 | }) async {
50 | logger.debug('UpdateMemoUsecase.save()');
51 | // ドメインを呼んで内容をチェックする
52 | final validater = MemoValidater(
53 | maxLength: memoConfig.maxLength,
54 | );
55 | final ok = validater.validateLength(
56 | edittingNotifier.value,
57 | );
58 | // ルール違反のときはダイアログを表示して終了
59 | if (!ok) {
60 | onValidateFailure();
61 | return;
62 | }
63 | // リスト一覧のメモを上書きして状態を変更
64 | listNotifier.replace(
65 | edittingNotifier.value,
66 | );
67 | // 成功を知らせる
68 | onSuccess();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/application/di/usecases.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 | import 'package:my_app/application/state/memo_list_provider.dart';
3 | import 'package:my_app/application/state/editting_memo_provider.dart';
4 | import 'package:my_app/application/usecases/add_memo.dart';
5 | import 'package:my_app/application/usecases/delete_memo.dart';
6 | import 'package:my_app/application/usecases/init_app.dart';
7 | import 'package:my_app/application/usecases/update_memo.dart';
8 | import 'package:my_app/application/di/infrastructure.dart';
9 |
10 | /// Init App
11 | final initAppProvider = Provider(
12 | (ref) {
13 | final logger = ref.read(loggerProvider);
14 | final firebase = ref.watch(firebaseProvider);
15 | final listNotifier = ref.watch(memoListProvider.notifier);
16 | return InitAppUsecase(
17 | logger: logger,
18 | firebase: firebase,
19 | listNotifier: listNotifier,
20 | );
21 | },
22 | );
23 |
24 | /// Add Memo
25 | final addMemoProvider = Provider(
26 | (ref) {
27 | final logger = ref.read(loggerProvider);
28 | final firebase = ref.watch(firebaseProvider);
29 | final listNotifier = ref.watch(memoListProvider.notifier);
30 | return AddMemoUsecase(
31 | logger: logger,
32 | firebase: firebase,
33 | listNotifier: listNotifier,
34 | );
35 | },
36 | );
37 |
38 | /// Delete Memo
39 | final deleteMemoProvider = Provider(
40 | (ref) {
41 | final logger = ref.read(loggerProvider);
42 | final firebase = ref.watch(firebaseProvider);
43 | final listNotifier = ref.watch(memoListProvider.notifier);
44 | return DeleteMemoUsecase(
45 | logger: logger,
46 | firebase: firebase,
47 | listNotifier: listNotifier,
48 | );
49 | },
50 | );
51 |
52 | /// Update Memo
53 | final updateMemoProvider = Provider.family(
54 | (ref, id) {
55 | final logger = ref.read(loggerProvider);
56 | final firebase = ref.watch(firebaseProvider);
57 | final listNotifier = ref.watch(memoListProvider.notifier);
58 | final edittingNotifier = ref.watch(edittingMemoProvider(id).notifier);
59 | return UpdateMemoUsecase(
60 | logger: logger,
61 | firebase: firebase,
62 | listNotifier: listNotifier,
63 | edittingNotifier: edittingNotifier,
64 | );
65 | },
66 | );
67 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion flutter.compileSdkVersion
30 | ndkVersion flutter.ndkVersion
31 |
32 | compileOptions {
33 | sourceCompatibility JavaVersion.VERSION_1_8
34 | targetCompatibility JavaVersion.VERSION_1_8
35 | }
36 |
37 | kotlinOptions {
38 | jvmTarget = '1.8'
39 | }
40 |
41 | sourceSets {
42 | main.java.srcDirs += 'src/main/kotlin'
43 | }
44 |
45 | defaultConfig {
46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
47 | applicationId "com.example.my_app"
48 | // You can update the following values to match your application needs.
49 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
50 | minSdkVersion flutter.minSdkVersion
51 | targetSdkVersion flutter.targetSdkVersion
52 | versionCode flutterVersionCode.toInteger()
53 | versionName flutterVersionName
54 | }
55 |
56 | buildTypes {
57 | release {
58 | // TODO: Add your own signing config for the release build.
59 | // Signing with the debug keys for now, so `flutter run --release` works.
60 | signingConfig signingConfigs.debug
61 | }
62 | }
63 | }
64 |
65 | flutter {
66 | source '../..'
67 | }
68 |
69 | dependencies {
70 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
71 | }
72 |
--------------------------------------------------------------------------------
/.vscode/dart.code-snippets:
--------------------------------------------------------------------------------
1 | {
2 | "@freezed": {
3 | "prefix": "@freezed",
4 | "scope": "dart",
5 | "body": [
6 | "import 'package:freezed_annotation/freezed_annotation.dart';",
7 | "part '$TM_FILENAME_BASE.freezed.dart';",
8 | "",
9 | "@freezed",
10 | "class $1 with _$$1 {",
11 | " const factory $1({",
12 | " required int data1,",
13 | " required int data2,",
14 | " required int data3,",
15 | " }) = _$1;",
16 | "}"
17 | ]
18 | },
19 | "@freezed_json": {
20 | "prefix": "@freezed_json",
21 | "scope": "dart",
22 | "body": [
23 | "import 'package:freezed_annotation/freezed_annotation.dart';",
24 | "part '$TM_FILENAME_BASE.freezed.dart';",
25 | "part '$TM_FILENAME_BASE.g.dart';",
26 | "",
27 | "@freezed",
28 | "class ${1:Xxx} with _$${1:Xxx} {",
29 | " const factory ${1:Xxx}({",
30 | "",
31 | " // required ,",
32 | "",
33 | " }) = _${1:Xxx};",
34 | " factory ${1:Xxx}.fromJson(Map json) => _$${1:Xxx}FromJson(json);",
35 | "}"
36 | ]
37 | },
38 | "build_runner": {
39 | "prefix": "build_runner",
40 | "body": ["flutter pub run build_runner build --delete-conflicting-outputs"]
41 | },
42 | "state_provider": {
43 | "prefix": "state_provider",
44 | "scope": "dart",
45 | "body": [
46 | "final $1Provider = StateProvider((ref) {",
47 | " return 0;",
48 | "});"
49 | ]
50 | },
51 | "consumer": {
52 | "prefix": "consumer",
53 | "scope": "dart",
54 | "body": [
55 | "class $1 extends ConsumerWidget {",
56 | " const $1({",
57 | " super.key,",
58 | " });",
59 | "",
60 | " @override",
61 | " Widget build(BuildContext context, WidgetRef ref) {",
62 | " return Container();",
63 | " }",
64 | "}"
65 | ]
66 | },
67 | "enum_codable": {
68 | "prefix": "enum_codable",
69 | "scope": "dart",
70 | "body": [
71 | "enum $1 {",
72 | " aaa(0),",
73 | " bbb(1),",
74 | " ccc(2);",
75 | "",
76 | " const $1(this.encoded);",
77 | " final int encoded;",
78 | " factory $1.fromJson(dynamic json) {",
79 | " return $1.values.firstWhere((value) {",
80 | " return value.encoded == json;",
81 | " });",
82 | " }",
83 | " dynamic toJson() => encoded;",
84 | "}"
85 | ]
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/lib/presentation/pages/list.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_hooks/flutter_hooks.dart';
3 | import 'package:hooks_riverpod/hooks_riverpod.dart';
4 | import 'package:my_app/application/di/usecases.dart';
5 | import 'package:my_app/application/di/infrastructure.dart';
6 | import 'package:my_app/application/state/memo_list_provider.dart';
7 | import 'package:my_app/presentation/router/page_path.dart';
8 | import 'package:my_app/presentation/router/go_router.dart';
9 | import 'package:my_app/presentation/widgets/add_button.dart';
10 | import 'package:my_app/presentation/widgets/memo_card.dart';
11 | import 'package:my_app/presentation/theme/sizes.dart';
12 |
13 | /// 一覧画面
14 | class ListPage extends HookConsumerWidget {
15 | const ListPage({
16 | super.key,
17 | });
18 |
19 | @override
20 | Widget build(BuildContext context, WidgetRef ref) {
21 | /// logger
22 | final logger = ref.watch(loggerProvider);
23 | logger.debug('ListPage.build()');
24 |
25 | // 画面が表示された時に処理をする
26 | useEffect(() {
27 | // スプラッシュ画面がないのでここで初期化
28 | final usecase = ref.read(initAppProvider);
29 | usecase.execute();
30 | return null;
31 | }, const []);
32 |
33 | /// メモ一覧
34 | final memoList = ref.watch(memoListProvider);
35 |
36 | /// リスト
37 | final listView = ListView.builder(
38 | itemCount: memoList.length,
39 | itemBuilder: (context, index) {
40 | final memo = memoList[index];
41 | return MemoCard(
42 | memo: memoList[index],
43 | onPressed: () {
44 | // 編集画面へ進む
45 | final router = ref.read(goRouterProvider);
46 | router.pushNamed(
47 | PageId.edit.routeName,
48 | pathParameters: {'id': memo.id},
49 | );
50 | },
51 | onPressedDelete: () {
52 | // ユースケースを呼び出す
53 | final usecase = ref.read(deleteMemoProvider);
54 | usecase.deleteMemo(memo.id);
55 | },
56 | );
57 | },
58 | );
59 |
60 | /// 追加ボタン
61 | final addButton = AddButton(
62 | onPressed: () {
63 | // ユースケースを呼び出す
64 | final usecase = ref.read(addMemoProvider);
65 | usecase.addNewMemo();
66 | },
67 | );
68 |
69 | /// 画面レイアウト
70 | return Scaffold(
71 | floatingActionButton: addButton,
72 | body: Padding(
73 | padding: const EdgeInsets.all(RawSize.p4),
74 | child: listView,
75 | ),
76 | );
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/lib/presentation/widgets/memo_card.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:my_app/domain/types/memo.dart';
3 | import 'package:my_app/presentation/theme/colors.dart';
4 | import 'package:my_app/presentation/theme/fonts.dart';
5 | import 'package:my_app/presentation/theme/sizes.dart';
6 | import 'package:my_app/presentation/widgets/delete_button.dart';
7 | import 'package:my_app/presentation/widgets/status_image.dart';
8 |
9 | /// メモカード
10 | class MemoCard extends StatelessWidget {
11 | const MemoCard({
12 | super.key,
13 | required this.memo,
14 | required this.onPressed,
15 | required this.onPressedDelete,
16 | });
17 |
18 | /// 表示するメモ
19 | final Memo memo;
20 |
21 | /// コールバック カード全体
22 | final VoidCallback onPressed;
23 |
24 | /// コールバック 削除
25 | final VoidCallback onPressedDelete;
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | /// ステータス表示エリア
30 | final statusLabel = Container(
31 | width: RawSize.p60,
32 | alignment: Alignment.center,
33 | padding: const EdgeInsets.all(RawSize.p8),
34 | color: BrandColor.bananaYellow,
35 | child: StatusImage(status: memo.status),
36 | );
37 |
38 | /// メモの文字を表示するエリア
39 | final textArea = Container(
40 | alignment: Alignment.centerLeft,
41 | child: Text(
42 | memo.text,
43 | textAlign: TextAlign.left,
44 | style: BrandText.bodyS,
45 | maxLines: 1,
46 | ),
47 | );
48 |
49 | /// ボタンを並べるエリア
50 | final actionsRow = Row(
51 | children: [
52 | const Spacer(),
53 | DeleteButton(onPressed: onPressedDelete),
54 | ],
55 | );
56 |
57 | /// レイアウト
58 | final layouts = SizedBox(
59 | height: RawSize.p90,
60 | child: Row(
61 | mainAxisSize: MainAxisSize.min,
62 | children: [
63 | statusLabel,
64 | Expanded(
65 | child: Container(
66 | padding: const EdgeInsets.all(RawSize.p4),
67 | child: Column(
68 | mainAxisSize: MainAxisSize.min,
69 | children: [
70 | Expanded(child: textArea),
71 | actionsRow,
72 | ],
73 | ),
74 | ),
75 | ),
76 | ],
77 | ),
78 | );
79 |
80 | /// タップを検知
81 | return Card(
82 | clipBehavior: Clip.hardEdge,
83 | child: InkWell(
84 | onTap: onPressed,
85 | child: layouts,
86 | ),
87 | );
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/lib/infrastructure/log/fake_logger.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:my_app/application/interfaces/logger.dart';
3 | import 'package:my_app/infrastructure/log/log.dart';
4 | import 'package:my_app/infrastructure/log/log_level.dart';
5 |
6 | /// 保存機能を持たず出力するだけのシンプルなロガー
7 | class FakeLogger implements Logger {
8 | FakeLogger({
9 | this.consoleFilterTag,
10 | this.consoleFilterMinLevel = LogLevel.debug,
11 | });
12 | final String? consoleFilterTag;
13 | final LogLevel consoleFilterMinLevel;
14 |
15 | final _logLevelPrefixes = {
16 | LogLevel.fatal: 'FATAL',
17 | LogLevel.error: 'ERROR',
18 | LogLevel.warn: 'WARN',
19 | LogLevel.info: 'INFO',
20 | LogLevel.debug: 'DEBUG',
21 | LogLevel.trace: 'TRACE',
22 | };
23 |
24 | void _printToConsoleIfNeeded(Log log) {
25 | // filter by tag
26 | if (consoleFilterTag != null) {
27 | final shouldPrint = log.tags.contains(consoleFilterTag);
28 | if (!shouldPrint) {
29 | return;
30 | }
31 | }
32 | // filter by log level
33 | if (log.level.priority < consoleFilterMinLevel.priority) {
34 | return;
35 | }
36 | final levelPrefix = _logLevelPrefixes[log.level] ?? 'UNKOWN_LOG_LEVEL:';
37 | final msg = log.msg;
38 | final text = '$levelPrefix $msg';
39 | debugPrint(text);
40 | }
41 |
42 | void _onCreateLog(Log log) {
43 | _printToConsoleIfNeeded(log);
44 | }
45 |
46 | @override
47 | void fatal(String msg) {
48 | final now = DateTime.now().toIso8601String();
49 | final log = Log(
50 | createdAt: now,
51 | level: LogLevel.fatal,
52 | tags: [],
53 | msg: msg,
54 | );
55 | _onCreateLog(log);
56 | }
57 |
58 | @override
59 | void error(String msg) {
60 | final now = DateTime.now().toIso8601String();
61 | final log = Log(
62 | createdAt: now,
63 | level: LogLevel.error,
64 | tags: [],
65 | msg: msg,
66 | );
67 | _onCreateLog(log);
68 | }
69 |
70 | @override
71 | void info(String msg) {
72 | final now = DateTime.now().toIso8601String();
73 | final log = Log(
74 | createdAt: now,
75 | level: LogLevel.info,
76 | tags: [],
77 | msg: msg,
78 | );
79 | _onCreateLog(log);
80 | }
81 |
82 | @override
83 | void debug(String msg) {
84 | final now = DateTime.now().toIso8601String();
85 | final log = Log(
86 | createdAt: now,
87 | level: LogLevel.debug,
88 | tags: [],
89 | msg: msg,
90 | );
91 | _onCreateLog(log);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/lib/presentation/dialogs/warn.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:my_app/presentation/theme/colors.dart';
3 | import 'package:my_app/presentation/theme/fonts.dart';
4 | import 'package:my_app/presentation/theme/l10n.dart';
5 | import 'package:my_app/presentation/theme/sizes.dart';
6 |
7 | /// カスタムダイアログ 警告用
8 | class WarnDialog extends StatelessWidget {
9 | const WarnDialog({
10 | super.key,
11 | required this.message,
12 | required this.onPressedOk,
13 | });
14 |
15 | final String message;
16 | final VoidCallback onPressedOk;
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | final messageArea = Expanded(
21 | child: Container(
22 | padding: const EdgeInsets.all(RawSize.p4),
23 | alignment: Alignment.center,
24 | child: Text(
25 | message,
26 | style: BrandText.bodyM,
27 | maxLines: 5,
28 | ),
29 | ),
30 | );
31 |
32 | final buttonArea = SizedBox(
33 | width: double.infinity,
34 | height: RawSize.p40,
35 | child: TextButton(
36 | style: TextButton.styleFrom(
37 | backgroundColor: BrandColor.bananaYellow,
38 | shape: const RoundedRectangleBorder(
39 | borderRadius: BorderRadius.all(Radius.zero),
40 | ),
41 | ),
42 | onPressed: onPressedOk,
43 | child: Text(
44 | L10n.ok,
45 | style: BrandText.titleS.copyWith(
46 | color: BrandColor.white,
47 | ),
48 | ),
49 | ),
50 | );
51 |
52 | return Scaffold(
53 | backgroundColor: Colors.transparent,
54 | body: Center(
55 | child: Container(
56 | width: 300,
57 | height: 300,
58 | decoration: BoxDecoration(
59 | color: Colors.white,
60 | border: Border.all(
61 | color: BrandColor.bananaYellow,
62 | width: RawSize.p4,
63 | ),
64 | borderRadius: BorderRadius.circular(RawSize.p8),
65 | ),
66 | alignment: Alignment.center,
67 | child: Column(
68 | children: [
69 | messageArea,
70 | buttonArea,
71 | ],
72 | ),
73 | ),
74 | ),
75 | );
76 | }
77 | }
78 |
79 | void showWarnDialog(
80 | BuildContext context,
81 | String message,
82 | ) {
83 | showDialog(
84 | context: context,
85 | builder: (context) {
86 | return WarnDialog(
87 | message: message,
88 | onPressedOk: () {
89 | Navigator.of(context).pop();
90 | },
91 | );
92 | },
93 | );
94 | }
95 |
--------------------------------------------------------------------------------
/lib/infrastructure/log/logger.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:my_app/application/interfaces/logger.dart';
3 | import 'package:my_app/infrastructure/log/log.dart';
4 | import 'package:my_app/infrastructure/log/log_level.dart';
5 |
6 | /// 一定数のログを管理できる設定変更可能なロガー
7 | class DefaultLogger implements Logger {
8 | DefaultLogger({
9 | this.maxRecentLogs = 200,
10 | this.logPrefix = '',
11 | this.consoleFilterTag,
12 | this.consoleFilterMinLevel = LogLevel.debug,
13 | });
14 | final int maxRecentLogs;
15 | final List recentLogs = [];
16 | final String logPrefix;
17 | final String? consoleFilterTag;
18 | final LogLevel consoleFilterMinLevel;
19 |
20 | final _logLevelPrefixes = {
21 | LogLevel.fatal: 'FATAL',
22 | LogLevel.error: 'ERROR',
23 | LogLevel.warn: 'WARN',
24 | LogLevel.info: 'INFO',
25 | LogLevel.debug: 'DEBUG',
26 | LogLevel.trace: 'TRACE',
27 | };
28 |
29 | void _printToConsoleIfNeeded(Log log) {
30 | // filter by tag
31 | if (consoleFilterTag != null) {
32 | final shouldPrint = log.tags.contains(consoleFilterTag);
33 | if (!shouldPrint) {
34 | return;
35 | }
36 | }
37 | // filter by log level
38 | if (log.level.priority < consoleFilterMinLevel.priority) {
39 | return;
40 | }
41 | final levelPrefix = _logLevelPrefixes[log.level] ?? 'UNKOWN_LOG_LEVEL:';
42 | final msg = log.msg;
43 | final text = '$logPrefix$levelPrefix $msg';
44 | debugPrint(text);
45 | }
46 |
47 | void _onCreateLog(Log log) {
48 | if (recentLogs.length >= maxRecentLogs) {
49 | recentLogs.removeAt(0);
50 | }
51 | _printToConsoleIfNeeded(log);
52 | recentLogs.add(log);
53 | }
54 |
55 | @override
56 | void fatal(String msg) {
57 | final now = DateTime.now().toIso8601String();
58 | final log = Log(
59 | createdAt: now,
60 | level: LogLevel.fatal,
61 | tags: [],
62 | msg: msg,
63 | );
64 | _onCreateLog(log);
65 | }
66 |
67 | @override
68 | void error(String msg) {
69 | final now = DateTime.now().toIso8601String();
70 | final log = Log(
71 | createdAt: now,
72 | level: LogLevel.error,
73 | tags: [],
74 | msg: msg,
75 | );
76 | _onCreateLog(log);
77 | }
78 |
79 | @override
80 | void info(String msg) {
81 | final now = DateTime.now().toIso8601String();
82 | final log = Log(
83 | createdAt: now,
84 | level: LogLevel.info,
85 | tags: [],
86 | msg: msg,
87 | );
88 | _onCreateLog(log);
89 | }
90 |
91 | @override
92 | void debug(String msg) {
93 | final now = DateTime.now().toIso8601String();
94 | final log = Log(
95 | createdAt: now,
96 | level: LogLevel.debug,
97 | tags: [],
98 | msg: msg,
99 | );
100 | _onCreateLog(log);
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
69 |
71 |
77 |
78 |
79 |
80 |
82 |
83 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/lib/presentation/pages/edit.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:hooks_riverpod/hooks_riverpod.dart';
3 | import 'package:my_app/application/di/usecases.dart';
4 | import 'package:my_app/application/di/infrastructure.dart';
5 | import 'package:my_app/application/state/editting_memo_provider.dart';
6 | import 'package:my_app/presentation/theme/colors.dart';
7 | import 'package:my_app/presentation/theme/l10n.dart';
8 | import 'package:my_app/presentation/theme/sizes.dart';
9 | import 'package:my_app/presentation/widgets/gap.dart';
10 | import 'package:my_app/presentation/widgets/save_button.dart';
11 | import 'package:my_app/presentation/widgets/status_button.dart';
12 | import 'package:my_app/presentation/widgets/text_edit_form.dart';
13 | import 'package:my_app/presentation/widgets/status_text.dart';
14 | import 'package:my_app/presentation/dialogs/warn.dart';
15 | import 'package:my_app/presentation/router/go_router.dart';
16 |
17 | /// 編集画面
18 | class EditPage extends ConsumerWidget {
19 | const EditPage({
20 | super.key,
21 | required this.memoId,
22 | });
23 |
24 | final String memoId;
25 |
26 | @override
27 | Widget build(BuildContext context, WidgetRef ref) {
28 | /// logger
29 | final logger = ref.watch(loggerProvider);
30 | logger.debug('EditPage.build()');
31 |
32 | /// 編集中のメモ
33 | final memo = ref.watch(edittingMemoProvider(memoId));
34 |
35 | /// ステータスボタン
36 | final statusButton = SizedBox(
37 | width: RawSize.p60,
38 | height: RawSize.p60,
39 | child: StatusButton(
40 | status: memo.status,
41 | onPressed: () {
42 | // ユースケースを呼び出す
43 | final usecase = ref.read(updateMemoProvider(memoId));
44 | usecase.editStatus();
45 | },
46 | ),
47 | );
48 |
49 | /// ステータス文字
50 | final statusText = StatusText(status: memo.status);
51 |
52 | /// テキスト編集フォーム
53 | final editForm = TextEditForm(
54 | value: memo.text,
55 | onChanged: (value) {
56 | // ユースケースを呼び出す
57 | final usecase = ref.read(updateMemoProvider(memoId));
58 | usecase.editText(value);
59 | },
60 | );
61 |
62 | /// 保存ボタン
63 | final saveButton = SaveButton(
64 | onPressed: () {
65 | // ユースケースを呼び出す
66 | final usecase = ref.read(updateMemoProvider(memoId));
67 | usecase.save(
68 | onValidateFailure: () {
69 | // 失敗したらダイアログを表示
70 | showWarnDialog(
71 | context,
72 | L10n.tooLongTextMesage,
73 | );
74 | },
75 | onSuccess: () {
76 | // 成功したら前の画面に戻る
77 | final router = ref.read(goRouterProvider);
78 | router.pop();
79 | },
80 | );
81 | },
82 | );
83 |
84 | /// 画面レイアウト
85 | return Scaffold(
86 | appBar: AppBar(
87 | backgroundColor: BrandColor.bananaYellow,
88 | title: const Text(L10n.edit),
89 | ),
90 | floatingActionButton: saveButton,
91 | body: Container(
92 | padding: const EdgeInsets.all(RawSize.p8),
93 | alignment: Alignment.center,
94 | child: Column(
95 | mainAxisSize: MainAxisSize.min,
96 | children: [
97 | const Spacer(flex: 1),
98 | Row(
99 | children: [
100 | statusButton,
101 | Gap.w(RawSize.p8),
102 | statusText,
103 | ],
104 | ),
105 | Gap.h(RawSize.p20),
106 | editForm,
107 | const Spacer(flex: 2),
108 | ],
109 | ),
110 | ),
111 | );
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/assets/fonts/OFL.txt:
--------------------------------------------------------------------------------
1 | Copyright 2012 Google Inc. All Rights Reserved.
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 | This license is copied below, and is also available with a FAQ at:
5 | http://scripts.sil.org/OFL
6 |
7 |
8 | -----------------------------------------------------------
9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | -----------------------------------------------------------
11 |
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide
14 | development of collaborative font projects, to support the font creation
15 | efforts of academic and linguistic communities, and to provide a free and
16 | open framework in which fonts may be shared and improved in partnership
17 | with others.
18 |
19 | The OFL allows the licensed fonts to be used, studied, modified and
20 | redistributed freely as long as they are not sold by themselves. The
21 | fonts, including any derivative works, can be bundled, embedded,
22 | redistributed and/or sold with any software provided that any reserved
23 | names are not used by derivative works. The fonts and derivatives,
24 | however, cannot be released under any other type of license. The
25 | requirement for fonts to remain under this license does not apply
26 | to any document created using the fonts or their derivatives.
27 |
28 | DEFINITIONS
29 | "Font Software" refers to the set of files released by the Copyright
30 | Holder(s) under this license and clearly marked as such. This may
31 | include source files, build scripts and documentation.
32 |
33 | "Reserved Font Name" refers to any names specified as such after the
34 | copyright statement(s).
35 |
36 | "Original Version" refers to the collection of Font Software components as
37 | distributed by the Copyright Holder(s).
38 |
39 | "Modified Version" refers to any derivative made by adding to, deleting,
40 | or substituting -- in part or in whole -- any of the components of the
41 | Original Version, by changing formats or by porting the Font Software to a
42 | new environment.
43 |
44 | "Author" refers to any designer, engineer, programmer, technical
45 | writer or other person who contributed to the Font Software.
46 |
47 | PERMISSION & CONDITIONS
48 | Permission is hereby granted, free of charge, to any person obtaining
49 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
50 | redistribute, and sell modified and unmodified copies of the Font
51 | Software, subject to the following conditions:
52 |
53 | 1) Neither the Font Software nor any of its individual components,
54 | in Original or Modified Versions, may be sold by itself.
55 |
56 | 2) Original or Modified Versions of the Font Software may be bundled,
57 | redistributed and/or sold with any software, provided that each copy
58 | contains the above copyright notice and this license. These can be
59 | included either as stand-alone text files, human-readable headers or
60 | in the appropriate machine-readable metadata fields within text or
61 | binary files as long as those fields can be easily viewed by the user.
62 |
63 | 3) No Modified Version of the Font Software may use the Reserved Font
64 | Name(s) unless explicit written permission is granted by the corresponding
65 | Copyright Holder. This restriction only applies to the primary font name as
66 | presented to the users.
67 |
68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69 | Software shall not be used to promote, endorse or advertise any
70 | Modified Version, except to acknowledge the contribution(s) of the
71 | Copyright Holder(s) and the Author(s) or with their explicit written
72 | permission.
73 |
74 | 5) The Font Software, modified or unmodified, in part or in whole,
75 | must be distributed entirely under this license, and must not be
76 | distributed under any other license. The requirement for fonts to
77 | remain under this license does not apply to any document created
78 | using the Font Software.
79 |
80 | TERMINATION
81 | This license becomes null and void if any of the above conditions are
82 | not met.
83 |
84 | DISCLAIMER
85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
94 |
--------------------------------------------------------------------------------
/lib/domain/types/memo.freezed.dart:
--------------------------------------------------------------------------------
1 | // coverage:ignore-file
2 | // GENERATED CODE - DO NOT MODIFY BY HAND
3 | // ignore_for_file: type=lint
4 | // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
5 |
6 | part of 'memo.dart';
7 |
8 | // **************************************************************************
9 | // FreezedGenerator
10 | // **************************************************************************
11 |
12 | T _$identity(T value) => value;
13 |
14 | final _privateConstructorUsedError = UnsupportedError(
15 | 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
16 |
17 | /// @nodoc
18 | mixin _$Memo {
19 | /// ID
20 | String get id => throw _privateConstructorUsedError;
21 |
22 | /// ステータス
23 | Status get status => throw _privateConstructorUsedError;
24 |
25 | /// 書かれた文字
26 | String get text => throw _privateConstructorUsedError;
27 |
28 | @JsonKey(ignore: true)
29 | $MemoCopyWith get copyWith => throw _privateConstructorUsedError;
30 | }
31 |
32 | /// @nodoc
33 | abstract class $MemoCopyWith<$Res> {
34 | factory $MemoCopyWith(Memo value, $Res Function(Memo) then) =
35 | _$MemoCopyWithImpl<$Res, Memo>;
36 | @useResult
37 | $Res call({String id, Status status, String text});
38 | }
39 |
40 | /// @nodoc
41 | class _$MemoCopyWithImpl<$Res, $Val extends Memo>
42 | implements $MemoCopyWith<$Res> {
43 | _$MemoCopyWithImpl(this._value, this._then);
44 |
45 | // ignore: unused_field
46 | final $Val _value;
47 | // ignore: unused_field
48 | final $Res Function($Val) _then;
49 |
50 | @pragma('vm:prefer-inline')
51 | @override
52 | $Res call({
53 | Object? id = null,
54 | Object? status = null,
55 | Object? text = null,
56 | }) {
57 | return _then(_value.copyWith(
58 | id: null == id
59 | ? _value.id
60 | : id // ignore: cast_nullable_to_non_nullable
61 | as String,
62 | status: null == status
63 | ? _value.status
64 | : status // ignore: cast_nullable_to_non_nullable
65 | as Status,
66 | text: null == text
67 | ? _value.text
68 | : text // ignore: cast_nullable_to_non_nullable
69 | as String,
70 | ) as $Val);
71 | }
72 | }
73 |
74 | /// @nodoc
75 | abstract class _$$_MemoCopyWith<$Res> implements $MemoCopyWith<$Res> {
76 | factory _$$_MemoCopyWith(_$_Memo value, $Res Function(_$_Memo) then) =
77 | __$$_MemoCopyWithImpl<$Res>;
78 | @override
79 | @useResult
80 | $Res call({String id, Status status, String text});
81 | }
82 |
83 | /// @nodoc
84 | class __$$_MemoCopyWithImpl<$Res> extends _$MemoCopyWithImpl<$Res, _$_Memo>
85 | implements _$$_MemoCopyWith<$Res> {
86 | __$$_MemoCopyWithImpl(_$_Memo _value, $Res Function(_$_Memo) _then)
87 | : super(_value, _then);
88 |
89 | @pragma('vm:prefer-inline')
90 | @override
91 | $Res call({
92 | Object? id = null,
93 | Object? status = null,
94 | Object? text = null,
95 | }) {
96 | return _then(_$_Memo(
97 | id: null == id
98 | ? _value.id
99 | : id // ignore: cast_nullable_to_non_nullable
100 | as String,
101 | status: null == status
102 | ? _value.status
103 | : status // ignore: cast_nullable_to_non_nullable
104 | as Status,
105 | text: null == text
106 | ? _value.text
107 | : text // ignore: cast_nullable_to_non_nullable
108 | as String,
109 | ));
110 | }
111 | }
112 |
113 | /// @nodoc
114 |
115 | class _$_Memo implements _Memo {
116 | const _$_Memo({required this.id, required this.status, required this.text});
117 |
118 | /// ID
119 | @override
120 | final String id;
121 |
122 | /// ステータス
123 | @override
124 | final Status status;
125 |
126 | /// 書かれた文字
127 | @override
128 | final String text;
129 |
130 | @override
131 | String toString() {
132 | return 'Memo(id: $id, status: $status, text: $text)';
133 | }
134 |
135 | @override
136 | bool operator ==(dynamic other) {
137 | return identical(this, other) ||
138 | (other.runtimeType == runtimeType &&
139 | other is _$_Memo &&
140 | (identical(other.id, id) || other.id == id) &&
141 | (identical(other.status, status) || other.status == status) &&
142 | (identical(other.text, text) || other.text == text));
143 | }
144 |
145 | @override
146 | int get hashCode => Object.hash(runtimeType, id, status, text);
147 |
148 | @JsonKey(ignore: true)
149 | @override
150 | @pragma('vm:prefer-inline')
151 | _$$_MemoCopyWith<_$_Memo> get copyWith =>
152 | __$$_MemoCopyWithImpl<_$_Memo>(this, _$identity);
153 | }
154 |
155 | abstract class _Memo implements Memo {
156 | const factory _Memo(
157 | {required final String id,
158 | required final Status status,
159 | required final String text}) = _$_Memo;
160 |
161 | @override
162 |
163 | /// ID
164 | String get id;
165 | @override
166 |
167 | /// ステータス
168 | Status get status;
169 | @override
170 |
171 | /// 書かれた文字
172 | String get text;
173 | @override
174 | @JsonKey(ignore: true)
175 | _$$_MemoCopyWith<_$_Memo> get copyWith => throw _privateConstructorUsedError;
176 | }
177 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | _fe_analyzer_shared:
5 | dependency: transitive
6 | description:
7 | name: _fe_analyzer_shared
8 | sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051
9 | url: "https://pub.dev"
10 | source: hosted
11 | version: "64.0.0"
12 | analyzer:
13 | dependency: transitive
14 | description:
15 | name: analyzer
16 | sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893"
17 | url: "https://pub.dev"
18 | source: hosted
19 | version: "6.2.0"
20 | args:
21 | dependency: transitive
22 | description:
23 | name: args
24 | sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
25 | url: "https://pub.dev"
26 | source: hosted
27 | version: "2.4.2"
28 | async:
29 | dependency: transitive
30 | description:
31 | name: async
32 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
33 | url: "https://pub.dev"
34 | source: hosted
35 | version: "2.11.0"
36 | boolean_selector:
37 | dependency: transitive
38 | description:
39 | name: boolean_selector
40 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
41 | url: "https://pub.dev"
42 | source: hosted
43 | version: "2.1.1"
44 | build:
45 | dependency: transitive
46 | description:
47 | name: build
48 | sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
49 | url: "https://pub.dev"
50 | source: hosted
51 | version: "2.4.1"
52 | build_config:
53 | dependency: transitive
54 | description:
55 | name: build_config
56 | sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
57 | url: "https://pub.dev"
58 | source: hosted
59 | version: "1.1.1"
60 | build_daemon:
61 | dependency: transitive
62 | description:
63 | name: build_daemon
64 | sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65"
65 | url: "https://pub.dev"
66 | source: hosted
67 | version: "4.0.0"
68 | build_resolvers:
69 | dependency: transitive
70 | description:
71 | name: build_resolvers
72 | sha256: "64e12b0521812d1684b1917bc80945625391cb9bdd4312536b1d69dcb6133ed8"
73 | url: "https://pub.dev"
74 | source: hosted
75 | version: "2.4.1"
76 | build_runner:
77 | dependency: "direct dev"
78 | description:
79 | name: build_runner
80 | sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b"
81 | url: "https://pub.dev"
82 | source: hosted
83 | version: "2.4.6"
84 | build_runner_core:
85 | dependency: transitive
86 | description:
87 | name: build_runner_core
88 | sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185
89 | url: "https://pub.dev"
90 | source: hosted
91 | version: "7.2.11"
92 | built_collection:
93 | dependency: transitive
94 | description:
95 | name: built_collection
96 | sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
97 | url: "https://pub.dev"
98 | source: hosted
99 | version: "5.1.1"
100 | built_value:
101 | dependency: transitive
102 | description:
103 | name: built_value
104 | sha256: a8de5955205b4d1dbbbc267daddf2178bd737e4bab8987c04a500478c9651e74
105 | url: "https://pub.dev"
106 | source: hosted
107 | version: "8.6.3"
108 | characters:
109 | dependency: transitive
110 | description:
111 | name: characters
112 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
113 | url: "https://pub.dev"
114 | source: hosted
115 | version: "1.3.0"
116 | checked_yaml:
117 | dependency: transitive
118 | description:
119 | name: checked_yaml
120 | sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
121 | url: "https://pub.dev"
122 | source: hosted
123 | version: "2.0.3"
124 | clock:
125 | dependency: transitive
126 | description:
127 | name: clock
128 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
129 | url: "https://pub.dev"
130 | source: hosted
131 | version: "1.1.1"
132 | code_builder:
133 | dependency: transitive
134 | description:
135 | name: code_builder
136 | sha256: "1be9be30396d7e4c0db42c35ea6ccd7cc6a1e19916b5dc64d6ac216b5544d677"
137 | url: "https://pub.dev"
138 | source: hosted
139 | version: "4.7.0"
140 | collection:
141 | dependency: transitive
142 | description:
143 | name: collection
144 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
145 | url: "https://pub.dev"
146 | source: hosted
147 | version: "1.18.0"
148 | convert:
149 | dependency: transitive
150 | description:
151 | name: convert
152 | sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
153 | url: "https://pub.dev"
154 | source: hosted
155 | version: "3.1.1"
156 | crypto:
157 | dependency: transitive
158 | description:
159 | name: crypto
160 | sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
161 | url: "https://pub.dev"
162 | source: hosted
163 | version: "3.0.3"
164 | dart_style:
165 | dependency: transitive
166 | description:
167 | name: dart_style
168 | sha256: abd7625e16f51f554ea244d090292945ec4d4be7bfbaf2ec8cccea568919d334
169 | url: "https://pub.dev"
170 | source: hosted
171 | version: "2.3.3"
172 | fake_async:
173 | dependency: transitive
174 | description:
175 | name: fake_async
176 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
177 | url: "https://pub.dev"
178 | source: hosted
179 | version: "1.3.1"
180 | file:
181 | dependency: transitive
182 | description:
183 | name: file
184 | sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
185 | url: "https://pub.dev"
186 | source: hosted
187 | version: "7.0.0"
188 | fixnum:
189 | dependency: transitive
190 | description:
191 | name: fixnum
192 | sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
193 | url: "https://pub.dev"
194 | source: hosted
195 | version: "1.1.0"
196 | flutter:
197 | dependency: "direct main"
198 | description: flutter
199 | source: sdk
200 | version: "0.0.0"
201 | flutter_hooks:
202 | dependency: "direct main"
203 | description:
204 | name: flutter_hooks
205 | sha256: "7c8db779c2d1010aa7f9ea3fbefe8f86524fcb87b69e8b0af31e1a4b55422dec"
206 | url: "https://pub.dev"
207 | source: hosted
208 | version: "0.20.3"
209 | flutter_lints:
210 | dependency: "direct dev"
211 | description:
212 | name: flutter_lints
213 | sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
214 | url: "https://pub.dev"
215 | source: hosted
216 | version: "2.0.3"
217 | flutter_riverpod:
218 | dependency: transitive
219 | description:
220 | name: flutter_riverpod
221 | sha256: e667e406a74d67715f1fa0bd941d9ded49aff72f3a9f4440a36aece4e8d457a7
222 | url: "https://pub.dev"
223 | source: hosted
224 | version: "2.4.3"
225 | flutter_test:
226 | dependency: "direct dev"
227 | description: flutter
228 | source: sdk
229 | version: "0.0.0"
230 | flutter_web_plugins:
231 | dependency: transitive
232 | description: flutter
233 | source: sdk
234 | version: "0.0.0"
235 | freezed:
236 | dependency: "direct dev"
237 | description:
238 | name: freezed
239 | sha256: "21bf2825311de65501d22e563e3d7605dff57fb5e6da982db785ae5372ff018a"
240 | url: "https://pub.dev"
241 | source: hosted
242 | version: "2.4.5"
243 | freezed_annotation:
244 | dependency: "direct main"
245 | description:
246 | name: freezed_annotation
247 | sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d
248 | url: "https://pub.dev"
249 | source: hosted
250 | version: "2.4.1"
251 | frontend_server_client:
252 | dependency: transitive
253 | description:
254 | name: frontend_server_client
255 | sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
256 | url: "https://pub.dev"
257 | source: hosted
258 | version: "3.2.0"
259 | glob:
260 | dependency: transitive
261 | description:
262 | name: glob
263 | sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
264 | url: "https://pub.dev"
265 | source: hosted
266 | version: "2.1.2"
267 | go_router:
268 | dependency: "direct main"
269 | description:
270 | name: go_router
271 | sha256: "1bd28265168045adb2df3da178bdbd44d37dddca0e7cfc867f8665d4f6b31f0c"
272 | url: "https://pub.dev"
273 | source: hosted
274 | version: "11.1.3"
275 | graphs:
276 | dependency: transitive
277 | description:
278 | name: graphs
279 | sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
280 | url: "https://pub.dev"
281 | source: hosted
282 | version: "2.3.1"
283 | hooks_riverpod:
284 | dependency: "direct main"
285 | description:
286 | name: hooks_riverpod
287 | sha256: "69dcb88acbc68c81fc27ec15a89a4e24b7812c83c13a6307a1a9366ada758541"
288 | url: "https://pub.dev"
289 | source: hosted
290 | version: "2.4.3"
291 | http_multi_server:
292 | dependency: transitive
293 | description:
294 | name: http_multi_server
295 | sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
296 | url: "https://pub.dev"
297 | source: hosted
298 | version: "3.2.1"
299 | http_parser:
300 | dependency: transitive
301 | description:
302 | name: http_parser
303 | sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
304 | url: "https://pub.dev"
305 | source: hosted
306 | version: "4.0.2"
307 | io:
308 | dependency: transitive
309 | description:
310 | name: io
311 | sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
312 | url: "https://pub.dev"
313 | source: hosted
314 | version: "1.0.4"
315 | js:
316 | dependency: transitive
317 | description:
318 | name: js
319 | sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
320 | url: "https://pub.dev"
321 | source: hosted
322 | version: "0.6.7"
323 | json_annotation:
324 | dependency: transitive
325 | description:
326 | name: json_annotation
327 | sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
328 | url: "https://pub.dev"
329 | source: hosted
330 | version: "4.8.1"
331 | leak_tracker:
332 | dependency: transitive
333 | description:
334 | name: leak_tracker
335 | sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
336 | url: "https://pub.dev"
337 | source: hosted
338 | version: "10.0.4"
339 | leak_tracker_flutter_testing:
340 | dependency: transitive
341 | description:
342 | name: leak_tracker_flutter_testing
343 | sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
344 | url: "https://pub.dev"
345 | source: hosted
346 | version: "3.0.3"
347 | leak_tracker_testing:
348 | dependency: transitive
349 | description:
350 | name: leak_tracker_testing
351 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
352 | url: "https://pub.dev"
353 | source: hosted
354 | version: "3.0.1"
355 | lints:
356 | dependency: transitive
357 | description:
358 | name: lints
359 | sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
360 | url: "https://pub.dev"
361 | source: hosted
362 | version: "2.1.1"
363 | logging:
364 | dependency: transitive
365 | description:
366 | name: logging
367 | sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
368 | url: "https://pub.dev"
369 | source: hosted
370 | version: "1.2.0"
371 | matcher:
372 | dependency: transitive
373 | description:
374 | name: matcher
375 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
376 | url: "https://pub.dev"
377 | source: hosted
378 | version: "0.12.16+1"
379 | material_color_utilities:
380 | dependency: transitive
381 | description:
382 | name: material_color_utilities
383 | sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
384 | url: "https://pub.dev"
385 | source: hosted
386 | version: "0.8.0"
387 | meta:
388 | dependency: transitive
389 | description:
390 | name: meta
391 | sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
392 | url: "https://pub.dev"
393 | source: hosted
394 | version: "1.12.0"
395 | mime:
396 | dependency: transitive
397 | description:
398 | name: mime
399 | sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
400 | url: "https://pub.dev"
401 | source: hosted
402 | version: "1.0.4"
403 | package_config:
404 | dependency: transitive
405 | description:
406 | name: package_config
407 | sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
408 | url: "https://pub.dev"
409 | source: hosted
410 | version: "2.1.0"
411 | path:
412 | dependency: transitive
413 | description:
414 | name: path
415 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
416 | url: "https://pub.dev"
417 | source: hosted
418 | version: "1.9.0"
419 | pool:
420 | dependency: transitive
421 | description:
422 | name: pool
423 | sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
424 | url: "https://pub.dev"
425 | source: hosted
426 | version: "1.5.1"
427 | pub_semver:
428 | dependency: transitive
429 | description:
430 | name: pub_semver
431 | sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
432 | url: "https://pub.dev"
433 | source: hosted
434 | version: "2.1.4"
435 | pubspec_parse:
436 | dependency: transitive
437 | description:
438 | name: pubspec_parse
439 | sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
440 | url: "https://pub.dev"
441 | source: hosted
442 | version: "1.2.3"
443 | riverpod:
444 | dependency: transitive
445 | description:
446 | name: riverpod
447 | sha256: "494bf2cfb4df30000273d3052bdb1cc1de738574c6b678f0beb146ea56f5e208"
448 | url: "https://pub.dev"
449 | source: hosted
450 | version: "2.4.3"
451 | shelf:
452 | dependency: transitive
453 | description:
454 | name: shelf
455 | sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
456 | url: "https://pub.dev"
457 | source: hosted
458 | version: "1.4.1"
459 | shelf_web_socket:
460 | dependency: transitive
461 | description:
462 | name: shelf_web_socket
463 | sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
464 | url: "https://pub.dev"
465 | source: hosted
466 | version: "1.0.4"
467 | sky_engine:
468 | dependency: transitive
469 | description: flutter
470 | source: sdk
471 | version: "0.0.99"
472 | source_gen:
473 | dependency: transitive
474 | description:
475 | name: source_gen
476 | sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16
477 | url: "https://pub.dev"
478 | source: hosted
479 | version: "1.4.0"
480 | source_span:
481 | dependency: transitive
482 | description:
483 | name: source_span
484 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
485 | url: "https://pub.dev"
486 | source: hosted
487 | version: "1.10.0"
488 | sprintf:
489 | dependency: transitive
490 | description:
491 | name: sprintf
492 | sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
493 | url: "https://pub.dev"
494 | source: hosted
495 | version: "7.0.0"
496 | stack_trace:
497 | dependency: transitive
498 | description:
499 | name: stack_trace
500 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
501 | url: "https://pub.dev"
502 | source: hosted
503 | version: "1.11.1"
504 | state_notifier:
505 | dependency: transitive
506 | description:
507 | name: state_notifier
508 | sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb
509 | url: "https://pub.dev"
510 | source: hosted
511 | version: "1.0.0"
512 | stream_channel:
513 | dependency: transitive
514 | description:
515 | name: stream_channel
516 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
517 | url: "https://pub.dev"
518 | source: hosted
519 | version: "2.1.2"
520 | stream_transform:
521 | dependency: transitive
522 | description:
523 | name: stream_transform
524 | sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
525 | url: "https://pub.dev"
526 | source: hosted
527 | version: "2.1.0"
528 | string_scanner:
529 | dependency: transitive
530 | description:
531 | name: string_scanner
532 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
533 | url: "https://pub.dev"
534 | source: hosted
535 | version: "1.2.0"
536 | term_glyph:
537 | dependency: transitive
538 | description:
539 | name: term_glyph
540 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
541 | url: "https://pub.dev"
542 | source: hosted
543 | version: "1.2.1"
544 | test_api:
545 | dependency: transitive
546 | description:
547 | name: test_api
548 | sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
549 | url: "https://pub.dev"
550 | source: hosted
551 | version: "0.7.0"
552 | timing:
553 | dependency: transitive
554 | description:
555 | name: timing
556 | sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
557 | url: "https://pub.dev"
558 | source: hosted
559 | version: "1.0.1"
560 | typed_data:
561 | dependency: transitive
562 | description:
563 | name: typed_data
564 | sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
565 | url: "https://pub.dev"
566 | source: hosted
567 | version: "1.3.2"
568 | uuid:
569 | dependency: "direct main"
570 | description:
571 | name: uuid
572 | sha256: b715b8d3858b6fa9f68f87d20d98830283628014750c2b09b6f516c1da4af2a7
573 | url: "https://pub.dev"
574 | source: hosted
575 | version: "4.1.0"
576 | vector_math:
577 | dependency: transitive
578 | description:
579 | name: vector_math
580 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
581 | url: "https://pub.dev"
582 | source: hosted
583 | version: "2.1.4"
584 | vm_service:
585 | dependency: transitive
586 | description:
587 | name: vm_service
588 | sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
589 | url: "https://pub.dev"
590 | source: hosted
591 | version: "14.2.1"
592 | watcher:
593 | dependency: transitive
594 | description:
595 | name: watcher
596 | sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
597 | url: "https://pub.dev"
598 | source: hosted
599 | version: "1.1.0"
600 | web_socket_channel:
601 | dependency: transitive
602 | description:
603 | name: web_socket_channel
604 | sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
605 | url: "https://pub.dev"
606 | source: hosted
607 | version: "2.4.0"
608 | yaml:
609 | dependency: transitive
610 | description:
611 | name: yaml
612 | sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
613 | url: "https://pub.dev"
614 | source: hosted
615 | version: "3.1.2"
616 | sdks:
617 | dart: ">=3.3.0 <4.0.0"
618 | flutter: ">=3.18.0-18.0.pre.54"
619 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 54;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXCopyFilesBuildPhase section */
19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
20 | isa = PBXCopyFilesBuildPhase;
21 | buildActionMask = 2147483647;
22 | dstPath = "";
23 | dstSubfolderSpec = 10;
24 | files = (
25 | );
26 | name = "Embed Frameworks";
27 | runOnlyForDeploymentPostprocessing = 0;
28 | };
29 | /* End PBXCopyFilesBuildPhase section */
30 |
31 | /* Begin PBXFileReference section */
32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
45 | /* End PBXFileReference section */
46 |
47 | /* Begin PBXFrameworksBuildPhase section */
48 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
49 | isa = PBXFrameworksBuildPhase;
50 | buildActionMask = 2147483647;
51 | files = (
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXFrameworksBuildPhase section */
56 |
57 | /* Begin PBXGroup section */
58 | 9740EEB11CF90186004384FC /* Flutter */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
65 | );
66 | name = Flutter;
67 | sourceTree = "";
68 | };
69 | 97C146E51CF9000F007C117D = {
70 | isa = PBXGroup;
71 | children = (
72 | 9740EEB11CF90186004384FC /* Flutter */,
73 | 97C146F01CF9000F007C117D /* Runner */,
74 | 97C146EF1CF9000F007C117D /* Products */,
75 | );
76 | sourceTree = "";
77 | };
78 | 97C146EF1CF9000F007C117D /* Products */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 97C146EE1CF9000F007C117D /* Runner.app */,
82 | );
83 | name = Products;
84 | sourceTree = "";
85 | };
86 | 97C146F01CF9000F007C117D /* Runner */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
92 | 97C147021CF9000F007C117D /* Info.plist */,
93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
97 | );
98 | path = Runner;
99 | sourceTree = "";
100 | };
101 | /* End PBXGroup section */
102 |
103 | /* Begin PBXNativeTarget section */
104 | 97C146ED1CF9000F007C117D /* Runner */ = {
105 | isa = PBXNativeTarget;
106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
107 | buildPhases = (
108 | 9740EEB61CF901F6004384FC /* Run Script */,
109 | 97C146EA1CF9000F007C117D /* Sources */,
110 | 97C146EB1CF9000F007C117D /* Frameworks */,
111 | 97C146EC1CF9000F007C117D /* Resources */,
112 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
114 | );
115 | buildRules = (
116 | );
117 | dependencies = (
118 | );
119 | name = Runner;
120 | productName = Runner;
121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
122 | productType = "com.apple.product-type.application";
123 | };
124 | /* End PBXNativeTarget section */
125 |
126 | /* Begin PBXProject section */
127 | 97C146E61CF9000F007C117D /* Project object */ = {
128 | isa = PBXProject;
129 | attributes = {
130 | LastUpgradeCheck = 1300;
131 | ORGANIZATIONNAME = "";
132 | TargetAttributes = {
133 | 97C146ED1CF9000F007C117D = {
134 | CreatedOnToolsVersion = 7.3.1;
135 | LastSwiftMigration = 1100;
136 | };
137 | };
138 | };
139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
140 | compatibilityVersion = "Xcode 9.3";
141 | developmentRegion = en;
142 | hasScannedForEncodings = 0;
143 | knownRegions = (
144 | en,
145 | Base,
146 | );
147 | mainGroup = 97C146E51CF9000F007C117D;
148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
149 | projectDirPath = "";
150 | projectRoot = "";
151 | targets = (
152 | 97C146ED1CF9000F007C117D /* Runner */,
153 | );
154 | };
155 | /* End PBXProject section */
156 |
157 | /* Begin PBXResourcesBuildPhase section */
158 | 97C146EC1CF9000F007C117D /* Resources */ = {
159 | isa = PBXResourcesBuildPhase;
160 | buildActionMask = 2147483647;
161 | files = (
162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
166 | );
167 | runOnlyForDeploymentPostprocessing = 0;
168 | };
169 | /* End PBXResourcesBuildPhase section */
170 |
171 | /* Begin PBXShellScriptBuildPhase section */
172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
173 | isa = PBXShellScriptBuildPhase;
174 | alwaysOutOfDate = 1;
175 | buildActionMask = 2147483647;
176 | files = (
177 | );
178 | inputPaths = (
179 | );
180 | name = "Thin Binary";
181 | outputPaths = (
182 | );
183 | runOnlyForDeploymentPostprocessing = 0;
184 | shellPath = /bin/sh;
185 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
186 | };
187 | 9740EEB61CF901F6004384FC /* Run Script */ = {
188 | isa = PBXShellScriptBuildPhase;
189 | alwaysOutOfDate = 1;
190 | buildActionMask = 2147483647;
191 | files = (
192 | );
193 | inputPaths = (
194 | );
195 | name = "Run Script";
196 | outputPaths = (
197 | );
198 | runOnlyForDeploymentPostprocessing = 0;
199 | shellPath = /bin/sh;
200 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
201 | };
202 | /* End PBXShellScriptBuildPhase section */
203 |
204 | /* Begin PBXSourcesBuildPhase section */
205 | 97C146EA1CF9000F007C117D /* Sources */ = {
206 | isa = PBXSourcesBuildPhase;
207 | buildActionMask = 2147483647;
208 | files = (
209 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
210 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
211 | );
212 | runOnlyForDeploymentPostprocessing = 0;
213 | };
214 | /* End PBXSourcesBuildPhase section */
215 |
216 | /* Begin PBXVariantGroup section */
217 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
218 | isa = PBXVariantGroup;
219 | children = (
220 | 97C146FB1CF9000F007C117D /* Base */,
221 | );
222 | name = Main.storyboard;
223 | sourceTree = "";
224 | };
225 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
226 | isa = PBXVariantGroup;
227 | children = (
228 | 97C147001CF9000F007C117D /* Base */,
229 | );
230 | name = LaunchScreen.storyboard;
231 | sourceTree = "";
232 | };
233 | /* End PBXVariantGroup section */
234 |
235 | /* Begin XCBuildConfiguration section */
236 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
237 | isa = XCBuildConfiguration;
238 | buildSettings = {
239 | ALWAYS_SEARCH_USER_PATHS = NO;
240 | CLANG_ANALYZER_NONNULL = YES;
241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
242 | CLANG_CXX_LIBRARY = "libc++";
243 | CLANG_ENABLE_MODULES = YES;
244 | CLANG_ENABLE_OBJC_ARC = YES;
245 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
246 | CLANG_WARN_BOOL_CONVERSION = YES;
247 | CLANG_WARN_COMMA = YES;
248 | CLANG_WARN_CONSTANT_CONVERSION = YES;
249 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
250 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
251 | CLANG_WARN_EMPTY_BODY = YES;
252 | CLANG_WARN_ENUM_CONVERSION = YES;
253 | CLANG_WARN_INFINITE_RECURSION = YES;
254 | CLANG_WARN_INT_CONVERSION = YES;
255 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
256 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
257 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
258 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
259 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
260 | CLANG_WARN_STRICT_PROTOTYPES = YES;
261 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
262 | CLANG_WARN_UNREACHABLE_CODE = YES;
263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
264 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
265 | COPY_PHASE_STRIP = NO;
266 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
267 | ENABLE_NS_ASSERTIONS = NO;
268 | ENABLE_STRICT_OBJC_MSGSEND = YES;
269 | GCC_C_LANGUAGE_STANDARD = gnu99;
270 | GCC_NO_COMMON_BLOCKS = YES;
271 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
272 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
273 | GCC_WARN_UNDECLARED_SELECTOR = YES;
274 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
275 | GCC_WARN_UNUSED_FUNCTION = YES;
276 | GCC_WARN_UNUSED_VARIABLE = YES;
277 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
278 | MTL_ENABLE_DEBUG_INFO = NO;
279 | SDKROOT = iphoneos;
280 | SUPPORTED_PLATFORMS = iphoneos;
281 | TARGETED_DEVICE_FAMILY = "1,2";
282 | VALIDATE_PRODUCT = YES;
283 | };
284 | name = Profile;
285 | };
286 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
287 | isa = XCBuildConfiguration;
288 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
289 | buildSettings = {
290 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
291 | CLANG_ENABLE_MODULES = YES;
292 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
293 | ENABLE_BITCODE = NO;
294 | INFOPLIST_FILE = Runner/Info.plist;
295 | LD_RUNPATH_SEARCH_PATHS = (
296 | "$(inherited)",
297 | "@executable_path/Frameworks",
298 | );
299 | PRODUCT_BUNDLE_IDENTIFIER = com.example.bananaMemo;
300 | PRODUCT_NAME = "$(TARGET_NAME)";
301 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
302 | SWIFT_VERSION = 5.0;
303 | VERSIONING_SYSTEM = "apple-generic";
304 | };
305 | name = Profile;
306 | };
307 | 97C147031CF9000F007C117D /* Debug */ = {
308 | isa = XCBuildConfiguration;
309 | buildSettings = {
310 | ALWAYS_SEARCH_USER_PATHS = NO;
311 | CLANG_ANALYZER_NONNULL = YES;
312 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
313 | CLANG_CXX_LIBRARY = "libc++";
314 | CLANG_ENABLE_MODULES = YES;
315 | CLANG_ENABLE_OBJC_ARC = YES;
316 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
317 | CLANG_WARN_BOOL_CONVERSION = YES;
318 | CLANG_WARN_COMMA = YES;
319 | CLANG_WARN_CONSTANT_CONVERSION = YES;
320 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
321 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
322 | CLANG_WARN_EMPTY_BODY = YES;
323 | CLANG_WARN_ENUM_CONVERSION = YES;
324 | CLANG_WARN_INFINITE_RECURSION = YES;
325 | CLANG_WARN_INT_CONVERSION = YES;
326 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
327 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
328 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
329 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
330 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
331 | CLANG_WARN_STRICT_PROTOTYPES = YES;
332 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
333 | CLANG_WARN_UNREACHABLE_CODE = YES;
334 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
335 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
336 | COPY_PHASE_STRIP = NO;
337 | DEBUG_INFORMATION_FORMAT = dwarf;
338 | ENABLE_STRICT_OBJC_MSGSEND = YES;
339 | ENABLE_TESTABILITY = YES;
340 | GCC_C_LANGUAGE_STANDARD = gnu99;
341 | GCC_DYNAMIC_NO_PIC = NO;
342 | GCC_NO_COMMON_BLOCKS = YES;
343 | GCC_OPTIMIZATION_LEVEL = 0;
344 | GCC_PREPROCESSOR_DEFINITIONS = (
345 | "DEBUG=1",
346 | "$(inherited)",
347 | );
348 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
349 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
350 | GCC_WARN_UNDECLARED_SELECTOR = YES;
351 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
352 | GCC_WARN_UNUSED_FUNCTION = YES;
353 | GCC_WARN_UNUSED_VARIABLE = YES;
354 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
355 | MTL_ENABLE_DEBUG_INFO = YES;
356 | ONLY_ACTIVE_ARCH = YES;
357 | SDKROOT = iphoneos;
358 | TARGETED_DEVICE_FAMILY = "1,2";
359 | };
360 | name = Debug;
361 | };
362 | 97C147041CF9000F007C117D /* Release */ = {
363 | isa = XCBuildConfiguration;
364 | buildSettings = {
365 | ALWAYS_SEARCH_USER_PATHS = NO;
366 | CLANG_ANALYZER_NONNULL = YES;
367 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
368 | CLANG_CXX_LIBRARY = "libc++";
369 | CLANG_ENABLE_MODULES = YES;
370 | CLANG_ENABLE_OBJC_ARC = YES;
371 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
372 | CLANG_WARN_BOOL_CONVERSION = YES;
373 | CLANG_WARN_COMMA = YES;
374 | CLANG_WARN_CONSTANT_CONVERSION = YES;
375 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
376 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
377 | CLANG_WARN_EMPTY_BODY = YES;
378 | CLANG_WARN_ENUM_CONVERSION = YES;
379 | CLANG_WARN_INFINITE_RECURSION = YES;
380 | CLANG_WARN_INT_CONVERSION = YES;
381 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
382 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
383 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
384 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
385 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
386 | CLANG_WARN_STRICT_PROTOTYPES = YES;
387 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
388 | CLANG_WARN_UNREACHABLE_CODE = YES;
389 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
390 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
391 | COPY_PHASE_STRIP = NO;
392 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
393 | ENABLE_NS_ASSERTIONS = NO;
394 | ENABLE_STRICT_OBJC_MSGSEND = YES;
395 | GCC_C_LANGUAGE_STANDARD = gnu99;
396 | GCC_NO_COMMON_BLOCKS = YES;
397 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
398 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
399 | GCC_WARN_UNDECLARED_SELECTOR = YES;
400 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
401 | GCC_WARN_UNUSED_FUNCTION = YES;
402 | GCC_WARN_UNUSED_VARIABLE = YES;
403 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
404 | MTL_ENABLE_DEBUG_INFO = NO;
405 | SDKROOT = iphoneos;
406 | SUPPORTED_PLATFORMS = iphoneos;
407 | SWIFT_COMPILATION_MODE = wholemodule;
408 | SWIFT_OPTIMIZATION_LEVEL = "-O";
409 | TARGETED_DEVICE_FAMILY = "1,2";
410 | VALIDATE_PRODUCT = YES;
411 | };
412 | name = Release;
413 | };
414 | 97C147061CF9000F007C117D /* Debug */ = {
415 | isa = XCBuildConfiguration;
416 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
417 | buildSettings = {
418 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
419 | CLANG_ENABLE_MODULES = YES;
420 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
421 | ENABLE_BITCODE = NO;
422 | INFOPLIST_FILE = Runner/Info.plist;
423 | LD_RUNPATH_SEARCH_PATHS = (
424 | "$(inherited)",
425 | "@executable_path/Frameworks",
426 | );
427 | PRODUCT_BUNDLE_IDENTIFIER = com.example.bananaMemo;
428 | PRODUCT_NAME = "$(TARGET_NAME)";
429 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
430 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
431 | SWIFT_VERSION = 5.0;
432 | VERSIONING_SYSTEM = "apple-generic";
433 | };
434 | name = Debug;
435 | };
436 | 97C147071CF9000F007C117D /* Release */ = {
437 | isa = XCBuildConfiguration;
438 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
439 | buildSettings = {
440 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
441 | CLANG_ENABLE_MODULES = YES;
442 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
443 | ENABLE_BITCODE = NO;
444 | INFOPLIST_FILE = Runner/Info.plist;
445 | LD_RUNPATH_SEARCH_PATHS = (
446 | "$(inherited)",
447 | "@executable_path/Frameworks",
448 | );
449 | PRODUCT_BUNDLE_IDENTIFIER = com.example.bananaMemo;
450 | PRODUCT_NAME = "$(TARGET_NAME)";
451 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
452 | SWIFT_VERSION = 5.0;
453 | VERSIONING_SYSTEM = "apple-generic";
454 | };
455 | name = Release;
456 | };
457 | /* End XCBuildConfiguration section */
458 |
459 | /* Begin XCConfigurationList section */
460 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
461 | isa = XCConfigurationList;
462 | buildConfigurations = (
463 | 97C147031CF9000F007C117D /* Debug */,
464 | 97C147041CF9000F007C117D /* Release */,
465 | 249021D3217E4FDB00AE95B9 /* Profile */,
466 | );
467 | defaultConfigurationIsVisible = 0;
468 | defaultConfigurationName = Release;
469 | };
470 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
471 | isa = XCConfigurationList;
472 | buildConfigurations = (
473 | 97C147061CF9000F007C117D /* Debug */,
474 | 97C147071CF9000F007C117D /* Release */,
475 | 249021D4217E4FDB00AE95B9 /* Profile */,
476 | );
477 | defaultConfigurationIsVisible = 0;
478 | defaultConfigurationName = Release;
479 | };
480 | /* End XCConfigurationList section */
481 | };
482 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
483 | }
484 |
--------------------------------------------------------------------------------