stuff
14
.metadata
|
|
@ -4,8 +4,8 @@
|
|||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49"
|
||||
channel: "stable"
|
||||
revision: "3e493a3e4d0a5c99fa7da51faae354e95a9a1abe"
|
||||
channel: "beta"
|
||||
|
||||
project_type: app
|
||||
|
||||
|
|
@ -13,11 +13,11 @@ project_type: app
|
|||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||
- platform: android
|
||||
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||
create_revision: 3e493a3e4d0a5c99fa7da51faae354e95a9a1abe
|
||||
base_revision: 3e493a3e4d0a5c99fa7da51faae354e95a9a1abe
|
||||
- platform: web
|
||||
create_revision: 3e493a3e4d0a5c99fa7da51faae354e95a9a1abe
|
||||
base_revision: 3e493a3e4d0a5c99fa7da51faae354e95a9a1abe
|
||||
|
||||
# User provided section
|
||||
|
||||
|
|
|
|||
219
README.md
|
|
@ -1,16 +1,215 @@
|
|||
# mnemo_cards
|
||||
# Mnemo Cards - Мобильное приложение для изучения языков
|
||||
|
||||
Mnemo
|
||||
Полнофункциональная система для изучения языков, включающая мобильное приложение, веб-сервер, телеграм-бот и веб-игры.
|
||||
|
||||
## Getting Started
|
||||
## 🏗️ Структура проекта
|
||||
|
||||
This project is a starting point for a Flutter application.
|
||||
Проект состоит из нескольких взаимосвязанных компонентов:
|
||||
|
||||
A few resources to get you started if this is your first Flutter project:
|
||||
### 📱 Мобильное приложение (`mnemo_cards/`)
|
||||
Основное Flutter приложение для iOS и Android с функциями:
|
||||
- Изучение языков через карточки
|
||||
- Интеграция с Firebase (Firestore, Analytics, Crashlytics)
|
||||
- Система покупок (YooKassa, In-App Purchase)
|
||||
- Реклама (Yandex Mobile Ads)
|
||||
- Локальные уведомления
|
||||
- Интеграция с веб-играми через WebView
|
||||
- Поддержка Telegram Web App
|
||||
|
||||
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||
**Технологии:** Flutter, BLoC, Auto Route, Firebase, WebView
|
||||
|
||||
For help getting started with Flutter development, view the
|
||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
### 🌐 Веб-приложение (`mnemo_cards_web/`)
|
||||
Веб-версия Flutter приложения с функциями:
|
||||
- Изучение языков через карточки в браузере
|
||||
- Интеграция с Firebase (Firestore, Analytics, Crashlytics)
|
||||
- Адаптивный дизайн для различных устройств
|
||||
- Синхронизация данных с мобильным приложением
|
||||
- Поддержка PWA (Progressive Web App)
|
||||
- Интеграция с веб-играми
|
||||
|
||||
**Технологии:** Flutter Web, BLoC, Auto Route, Firebase, PWA
|
||||
|
||||
### 🔧 Общие компоненты (`mnemo_cards_common/`)
|
||||
Общие DTO и утилиты для мобильного приложения:
|
||||
- Модели данных
|
||||
- Сетевые утилиты
|
||||
- JSON сериализация
|
||||
- Криптографические функции
|
||||
|
||||
### 🖥️ Backend сервер (`mnemo_cards_backend/`)
|
||||
Dart сервер на базе Shelf framework:
|
||||
- REST API для мобильного приложения
|
||||
- База данных Isar
|
||||
- Интеграция с Google APIs
|
||||
- Система платежей YooKassa
|
||||
- Периодические задачи
|
||||
- Swagger документация
|
||||
|
||||
**Технологии:** Dart, Shelf, Isar, Google APIs
|
||||
|
||||
### 🔧 Backend общие компоненты (`mnemo_cards_common_backend/`)
|
||||
Общие компоненты для backend:
|
||||
- Модели данных
|
||||
- Утилиты для работы с Isar
|
||||
- Общие бизнес-логика
|
||||
|
||||
### 🤖 Telegram бот (`mnemo_cards_telegram_bot/`)
|
||||
Telegram бот для управления приложением:
|
||||
- Административные функции
|
||||
- Распространение APK файлов
|
||||
- Управление пользователями
|
||||
- Интеграция с основным backend
|
||||
|
||||
**Технологии:** Dart, Teledart, Isar
|
||||
|
||||
### 🎮 Веб-игры и WebView Bridge (`games/`)
|
||||
Система веб-игр с безопасной коммуникацией через WebView:
|
||||
- **Host приложение** - Flutter приложение-контейнер
|
||||
- **Web приложения** - Flutter Web игры (bus_word_game, web_app1)
|
||||
- **Bridge Core** - система безопасной коммуникации
|
||||
- **Payloads** - типизированные сообщения между приложениями
|
||||
|
||||
**Архитектура:**
|
||||
- Изолированные payload'ы для каждого приложения
|
||||
- JavaScript bridge для WebView коммуникации
|
||||
- Типобезопасная обработка сообщений
|
||||
- Поддержка сложных сценариев (авторизация, quiz, нативные диалоги)
|
||||
|
||||
**Технологии:** Flutter Web, WebView, JavaScript Bridge, Melos
|
||||
|
||||
## 🚀 Быстрый старт
|
||||
|
||||
### Мобильное приложение
|
||||
```bash
|
||||
cd mnemo_cards
|
||||
flutter pub get
|
||||
flutter run
|
||||
```
|
||||
|
||||
### Веб-приложение
|
||||
```bash
|
||||
cd mnemo_cards_web
|
||||
flutter pub get
|
||||
flutter run -d chrome
|
||||
```
|
||||
|
||||
### Backend сервер
|
||||
```bash
|
||||
cd mnemo_cards_backend
|
||||
dart pub get
|
||||
dart run
|
||||
```
|
||||
|
||||
### Telegram бот
|
||||
```bash
|
||||
cd mnemo_cards_telegram_bot
|
||||
dart pub get
|
||||
dart run
|
||||
```
|
||||
|
||||
### Веб-игры
|
||||
```bash
|
||||
cd games
|
||||
melos bootstrap
|
||||
cd apps/host_app
|
||||
flutter run
|
||||
```
|
||||
|
||||
## 🔗 Зависимости между компонентами
|
||||
|
||||
```
|
||||
mnemo_cards
|
||||
├── mnemo_cards_common (DTO)
|
||||
├── games/mnemo_cards_web_bridge (WebView интеграция)
|
||||
└── Firebase/Backend API
|
||||
|
||||
mnemo_cards_web
|
||||
├── mnemo_cards_common (DTO)
|
||||
├── mnemo_cards_frontend_common (общие компоненты)
|
||||
├── games/payloads_shared (общие типы)
|
||||
└── Firebase/Backend API
|
||||
|
||||
mnemo_cards_backend
|
||||
├── mnemo_cards_common (общие DTO)
|
||||
├── mnemo_cards_common_backend (backend утилиты)
|
||||
└── Isar Database
|
||||
|
||||
mnemo_cards_telegram_bot
|
||||
├── mnemo_cards_common_backend
|
||||
└── Backend API
|
||||
|
||||
games/
|
||||
├── bridge_core (WebView коммуникация)
|
||||
├── payloads_shared (общие типы)
|
||||
└── apps/ (веб-приложения)
|
||||
```
|
||||
|
||||
## 📋 Основные функции
|
||||
|
||||
### Мобильное приложение
|
||||
- 📚 Изучение языков через карточки
|
||||
- 🎮 Интеграция с веб-играми
|
||||
- 💳 Система покупок и подписок
|
||||
- 📊 Аналитика и статистика
|
||||
- 🔔 Push уведомления
|
||||
- 🌐 Telegram Web App поддержка
|
||||
|
||||
### Веб-приложение
|
||||
- 📚 Изучение языков через карточки в браузере
|
||||
- 🎮 Интеграция с веб-играми
|
||||
- 💳 Система покупок и подписок
|
||||
- 📊 Аналитика и статистика
|
||||
- 🔄 Синхронизация с мобильным приложением
|
||||
- 📱 PWA поддержка для установки на устройство
|
||||
|
||||
### Backend
|
||||
- 🔐 Аутентификация и авторизация
|
||||
- 💾 Управление данными пользователей
|
||||
- 💰 Обработка платежей
|
||||
- 📈 Аналитика и метрики
|
||||
- 🔄 Периодические задачи
|
||||
- 📚 API для мобильного приложения
|
||||
|
||||
### Telegram бот
|
||||
- 👨💼 Административные функции
|
||||
- 📱 Распространение APK
|
||||
- 👥 Управление пользователями
|
||||
- 📊 Мониторинг системы
|
||||
|
||||
### Веб-игры
|
||||
- 🎯 Интерактивные игры для изучения языков
|
||||
- 🔗 Безопасная интеграция с мобильным приложением
|
||||
- 📊 Отслеживание прогресса
|
||||
- 🎨 Современный UI/UX
|
||||
|
||||
## 🛠️ Технологический стек
|
||||
|
||||
- **Frontend:** Flutter, Flutter Web
|
||||
- **Backend:** Dart, Shelf, Isar
|
||||
- **База данных:** Isar (локальная), Firestore (облачная)
|
||||
- **Аутентификация:** Firebase Auth, Google Sign-In
|
||||
- **Платежи:** YooKassa, In-App Purchase
|
||||
- **Аналитика:** Firebase Analytics, Crashlytics
|
||||
- **Реклама:** Yandex Mobile Ads
|
||||
- **Уведомления:** Firebase Messaging, Local Notifications
|
||||
- **Коммуникация:** WebView Bridge, REST API
|
||||
- **Мониторинг:** Telegram Bot
|
||||
|
||||
## 📱 Поддерживаемые платформы
|
||||
|
||||
- **iOS** - нативное приложение
|
||||
- **Android** - нативное приложение
|
||||
- **Web** - Flutter Web приложение и игры
|
||||
- **Telegram** - Web App интеграция
|
||||
|
||||
## 🔒 Безопасность
|
||||
|
||||
- Шифрование данных
|
||||
- Безопасная WebView коммуникация
|
||||
- Защита от root/jailbreak
|
||||
- Валидация платежей
|
||||
- Изоляция payload'ов в веб-играх
|
||||
|
||||
## 📄 Лицензия
|
||||
|
||||
Проект является приватным и не предназначен для публикации.
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
analyzer:
|
||||
errors:
|
||||
todo: info # чтобы отображать тудушки
|
||||
# unused_import: error # Лишние импорты в проекте не нужны
|
||||
# unused_local_variable: error # Неиспользуемые переменные в проекте не нужны
|
||||
# missing_required_param: error # Не пропускаем обязательные параметры
|
||||
# prefer_relative_imports: error # Относительные импорты в проекте
|
||||
# directives_ordering: error # Следим за порядком импортов в проекте
|
||||
unawaited_futures: error # Всегда резолвим Future
|
||||
13
android/.gitignore
vendored
|
|
@ -1,13 +0,0 @@
|
|||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
|
||||
# Remember to never publicly share your keystore.
|
||||
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||
key.properties
|
||||
**/*.keystore
|
||||
**/*.jks
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
plugins {
|
||||
id "com.android.application"
|
||||
// START: FlutterFire Configuration
|
||||
id 'com.google.gms.google-services'
|
||||
id 'com.google.firebase.crashlytics'
|
||||
// END: FlutterFire Configuration
|
||||
id "kotlin-android"
|
||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||
id "dev.flutter.flutter-gradle-plugin"
|
||||
}
|
||||
|
||||
def localProperties = new Properties()
|
||||
def localPropertiesFile = rootProject.file("local.properties")
|
||||
if (localPropertiesFile.exists()) {
|
||||
localPropertiesFile.withReader("UTF-8") { reader ->
|
||||
localProperties.load(reader)
|
||||
}
|
||||
}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
|
||||
if (flutterVersionCode == null) {
|
||||
flutterVersionCode = "1"
|
||||
}
|
||||
|
||||
def flutterVersionName = localProperties.getProperty("flutter.versionName")
|
||||
if (flutterVersionName == null) {
|
||||
flutterVersionName = "1.0"
|
||||
}
|
||||
|
||||
def keystoreProperties = new Properties()
|
||||
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.cinnabarflower.mnemo_cards"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.cinnabarflower.mnemo_cards"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||
minSdk = 25
|
||||
targetSdk = flutter.targetSdkVersion
|
||||
versionCode = flutterVersionCode.toInteger()
|
||||
versionName = flutterVersionName
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
keyPassword keystoreProperties['keyPassword']
|
||||
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||
storePassword keystoreProperties['storePassword']
|
||||
}
|
||||
debug {
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
keyPassword keystoreProperties['keyPassword']
|
||||
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||
storePassword keystoreProperties['storePassword']
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
debug {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source = "../.."
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
{
|
||||
"project_info": {
|
||||
"project_number": "701767851968",
|
||||
"project_id": "mnemo-cards",
|
||||
"storage_bucket": "mnemo-cards.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:701767851968:android:6190df55346394732f7225",
|
||||
"android_client_info": {
|
||||
"package_name": "com.cinnabarflower.mnemo_cards"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "701767851968-3jgootslus3ie76t682j4v7glletloud.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.cinnabarflower.mnemo_cards",
|
||||
"certificate_hash": "6df4f259b9c53ac01472c17df69e8c91494f3947"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "701767851968-5e6v0b5humhj0iu22t21nb9dtgt4tjus.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.cinnabarflower.mnemo_cards",
|
||||
"certificate_hash": "49bb5b6863c9e6d8db43e7eb4d54796a300d87fe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "701767851968-vqvjgf1u79jg924inm25bfuv4dg41t2u.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.cinnabarflower.mnemo_cards",
|
||||
"certificate_hash": "19f45c4abc59f7ce5f22e84376273ee1ee19bdc2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "701767851968-bud97rud1d9qtqju96addn31nhm0oofu.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyBGn7PVVDX-o7WipivtuBjdoH5nYEPsHms"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "701767851968-bud97rud1d9qtqju96addn31nhm0oofu.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "701767851968-8dqcmk706p08gujqbl2m9s4sq1aljibs.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.cinnabarflower.mnemoCards"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<application
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/launcher_icon"
|
||||
android:label="Mnemo cards">
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.ads.APPLICATION_ID"
|
||||
android:value="ca-app-pub-3940256099942544~3347511713" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:exported="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity=""
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="mnemocards" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
<!-- Required to query activities that can process text, see:
|
||||
https://developer.android.com/training/package-visibility and
|
||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||
|
||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.PROCESS_TEXT" />
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package com.cinnabarflower.mnemo_cards
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity: FlutterActivity()
|
||||
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 364 KiB |
|
Before Width: | Height: | Size: 69 B |
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
Before Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 364 KiB |
|
Before Width: | Height: | Size: 364 KiB |
|
Before Width: | Height: | Size: 69 B |
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
<item name="android:windowSplashScreenBackground">#ffffff</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
<item name="android:windowSplashScreenBackground">#ffffff</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<debug-overrides>
|
||||
<trust-anchors>
|
||||
<certificates src="system" />
|
||||
<certificates src="user" />
|
||||
</trust-anchors>
|
||||
</debug-overrides>
|
||||
</network-security-config>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.buildDir = "../build"
|
||||
subprojects {
|
||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||
}
|
||||
subprojects {
|
||||
project.evaluationDependsOn(":app")
|
||||
}
|
||||
|
||||
tasks.register("clean", Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
storePassword=345234
|
||||
keyPassword=345234
|
||||
keyAlias=upload
|
||||
storeFile=../../../../upload-keystore.jks
|
||||
BIN
android/pepk.jar
|
|
@ -1,43 +0,0 @@
|
|||
pluginManagement {
|
||||
def flutterSdkPath = {
|
||||
def properties = new Properties()
|
||||
file("local.properties").withInputStream { properties.load(it) }
|
||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||
return flutterSdkPath
|
||||
}()
|
||||
|
||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
// For yoo kassa
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url = uri("https://storage.googleapis.com/r8-releases/raw")
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools:r8:8.3.37")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "7.3.0" apply false
|
||||
// START: FlutterFire Configuration
|
||||
id "com.google.gms.google-services" version "4.3.15" apply false
|
||||
id "com.google.firebase.crashlytics" version "2.9.9" apply false
|
||||
|
||||
// END: FlutterFire Configuration
|
||||
id "org.jetbrains.kotlin.android" version "1.9.10" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
set -e -v
|
||||
cp ~/mnemo_cards/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk ~/mnemo_cards_telegram_bot/apks/admin_app.apk
|
||||
|
||||
|
Before Width: | Height: | Size: 169 KiB |
BIN
cerdo_512.png
|
Before Width: | Height: | Size: 178 KiB |
|
|
@ -1,3 +0,0 @@
|
|||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
||||
|
|
@ -1 +0,0 @@
|
|||
{"flutter":{"platforms":{"android":{"default":{"projectId":"mnemo-cards","appId":"1:701767851968:android:6190df55346394732f7225","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"mnemo-cards","appId":"1:701767851968:ios:5c9040634eac8c152f7225","uploadDebugSymbols":false,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"mnemo-cards","configurations":{"android":"1:701767851968:android:6190df55346394732f7225","ios":"1:701767851968:ios:5c9040634eac8c152f7225"}}}}}}
|
||||
2
funny_letters/build_web_debug.sh
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
flutter build web --profile --dart-define=Dart2jsOptimization=O0
|
||||
|
||||
1
funny_letters/codegen.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
flutter packages pub run build_runner build --delete-conflicting-outputs --verbose
|
||||
35
funny_letters/lib/runner/ui/button.dart
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
|
||||
const Color borderGray = Color(0xffABABAB);
|
||||
|
||||
class Button extends StatelessWidget {
|
||||
final String asset;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const Button(this.asset, this.onTap);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
width: 110.w,
|
||||
height: 60.h,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
border: Border.all(color: borderGray),
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Image(
|
||||
image: AssetImage(asset),
|
||||
width: 29.w,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
fit: BoxFit.scaleDown,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
1
funny_letters/run_web.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
dhttpd --path build/web --host 0.0.0.0 --port 8888
|
||||
405
games/ads_example/assets/vast_player_new.html
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Vast-Player Example</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vast-player@latest/dist/vast-player.min.js"></script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #000;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
#container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.loading {
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
.error {
|
||||
color: #ff6b6b;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
.ad-info {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
color: white;
|
||||
background: rgba(0,0,0,0.7);
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
font-size: 12px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.skip-button {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: rgba(0,0,0,0.8);
|
||||
color: white;
|
||||
border: 2px solid white;
|
||||
border-radius: 20px;
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
z-index: 1001;
|
||||
display: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.skip-button:hover {
|
||||
background: rgba(255,255,255,0.2);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.skip-button.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.skip-timer {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: rgba(0,0,0,0.8);
|
||||
color: white;
|
||||
border: 2px solid #ff6b6b;
|
||||
border-radius: 20px;
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
z-index: 1001;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.skip-timer.visible {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div class="loading">Загрузка рекламы...</div>
|
||||
<button id="skipButton" class="skip-button" onclick="skipAd()">Пропустить рекламу</button>
|
||||
<div id="skipTimer" class="skip-timer">Пропустить через: <span id="skipTime">5</span>с</div>
|
||||
</div>
|
||||
<script>
|
||||
(function(VASTPlayer) {
|
||||
'use strict';
|
||||
|
||||
var container = document.getElementById('container');
|
||||
var player = new VASTPlayer(container);
|
||||
|
||||
// Элементы для кнопки пропуска
|
||||
var skipButton = document.getElementById('skipButton');
|
||||
var skipTimer = document.getElementById('skipTimer');
|
||||
var skipTimeSpan = document.getElementById('skipTime');
|
||||
var skipTimerInterval = null;
|
||||
var skipOffset = 5; // секунд до возможности пропуска (по умолчанию)
|
||||
var skipOffsetFromVast = null; // будет установлено из VAST данных
|
||||
|
||||
// Функция для отправки событий в Flutter
|
||||
function sendToFlutter(eventName, data) {
|
||||
console.log('Sending to Flutter:', eventName, data);
|
||||
if (window.flutter_inappwebview) {
|
||||
window.flutter_inappwebview.callHandler(eventName, data);
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для парсинга времени из формата HH:MM:SS
|
||||
function parseTimeToSeconds(timeString) {
|
||||
if (!timeString) return 5; // по умолчанию 5 секунд
|
||||
|
||||
var parts = timeString.split(':');
|
||||
if (parts.length === 3) {
|
||||
var hours = parseInt(parts[0]) || 0;
|
||||
var minutes = parseInt(parts[1]) || 0;
|
||||
var seconds = parseInt(parts[2]) || 0;
|
||||
return hours * 3600 + minutes * 60 + seconds;
|
||||
}
|
||||
return 5; // по умолчанию 5 секунд
|
||||
}
|
||||
|
||||
// Функция для получения skipoffset из VAST данных
|
||||
function getSkipOffsetFromVast() {
|
||||
try {
|
||||
// Пытаемся получить skipoffset из VAST данных
|
||||
if (player && player.vastResponse && player.vastResponse.ads && player.vastResponse.ads.length > 0) {
|
||||
var ad = player.vastResponse.ads[0];
|
||||
if (ad.inLine && ad.inLine.creatives && ad.inLine.creatives.length > 0) {
|
||||
var creative = ad.inLine.creatives[0];
|
||||
if (creative.linear && creative.linear.skipoffset) {
|
||||
return parseTimeToSeconds(creative.linear.skipoffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Альтернативный способ - парсинг XML
|
||||
if (player && player.vastResponse && player.vastResponse.xml) {
|
||||
var xmlDoc = new DOMParser().parseFromString(player.vastResponse.xml, "text/xml");
|
||||
var linearElement = xmlDoc.querySelector("Linear");
|
||||
if (linearElement && linearElement.getAttribute("skipoffset")) {
|
||||
var skipoffset = linearElement.getAttribute("skipoffset");
|
||||
console.log('Found skipoffset in XML:', skipoffset);
|
||||
return parseTimeToSeconds(skipoffset);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error parsing VAST skipoffset:', e);
|
||||
}
|
||||
return skipOffset; // возвращаем значение по умолчанию
|
||||
}
|
||||
|
||||
// Функция для пропуска рекламы
|
||||
window.skipAd = function() {
|
||||
console.log('Skipping ad');
|
||||
player.skipAd();
|
||||
hideSkipElements();
|
||||
};
|
||||
|
||||
// Функция для показа кнопки пропуска
|
||||
function showSkipButton() {
|
||||
console.log('Showing skip button');
|
||||
skipButton.classList.add('visible');
|
||||
skipTimer.classList.remove('visible');
|
||||
if (skipTimerInterval) {
|
||||
clearInterval(skipTimerInterval);
|
||||
skipTimerInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для показа таймера пропуска
|
||||
function showSkipTimer() {
|
||||
console.log('Showing skip timer with offset:', skipOffsetFromVast);
|
||||
skipTimer.classList.add('visible');
|
||||
skipButton.classList.remove('visible');
|
||||
|
||||
var timeLeft = skipOffsetFromVast;
|
||||
skipTimeSpan.textContent = timeLeft;
|
||||
|
||||
skipTimerInterval = setInterval(function() {
|
||||
timeLeft--;
|
||||
skipTimeSpan.textContent = timeLeft;
|
||||
|
||||
if (timeLeft <= 0) {
|
||||
showSkipButton();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// Функция для скрытия элементов пропуска
|
||||
function hideSkipElements() {
|
||||
console.log('Hiding skip elements');
|
||||
skipButton.classList.remove('visible');
|
||||
skipTimer.classList.remove('visible');
|
||||
if (skipTimerInterval) {
|
||||
clearInterval(skipTimerInterval);
|
||||
skipTimerInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для загрузки рекламы с URL
|
||||
window.loadVastAd = function(vastUrl) {
|
||||
console.log('Loading VAST ad from URL:', vastUrl);
|
||||
container.innerHTML = '<div class="loading">Загрузка рекламы...</div>';
|
||||
hideSkipElements(); // Скрываем элементы пропуска при загрузке
|
||||
|
||||
// Восстанавливаем элементы пропуска
|
||||
container.innerHTML += '<button id="skipButton" class="skip-button" onclick="skipAd()">Пропустить рекламу</button>';
|
||||
container.innerHTML += '<div id="skipTimer" class="skip-timer">Пропустить через: <span id="skipTime">5</span>с</div>';
|
||||
|
||||
// Обновляем ссылки на элементы
|
||||
skipButton = document.getElementById('skipButton');
|
||||
skipTimer = document.getElementById('skipTimer');
|
||||
skipTimeSpan = document.getElementById('skipTime');
|
||||
|
||||
console.log('Skip elements restored:', {
|
||||
skipButton: skipButton,
|
||||
skipTimer: skipTimer,
|
||||
skipTimeSpan: skipTimeSpan
|
||||
});
|
||||
|
||||
player.load(vastUrl).then(function() {
|
||||
console.log('VAST ad loaded successfully');
|
||||
sendToFlutter('onAdLoaded');
|
||||
return player.startAd();
|
||||
}).catch(function(reason) {
|
||||
console.error('Failed to load ad:', reason);
|
||||
container.innerHTML = '<div class="error">Ошибка загрузки рекламы: ' + reason.message + '</div>';
|
||||
sendToFlutter('onAdError', reason);
|
||||
});
|
||||
};
|
||||
|
||||
// Функция для загрузки пользовательского XML
|
||||
window.loadCustomXml = function(xmlContent) {
|
||||
console.log('Loading custom XML ad, content length:', xmlContent.length);
|
||||
container.innerHTML = '<div class="loading">Загрузка пользовательской рекламы...</div>';
|
||||
hideSkipElements(); // Скрываем элементы пропуска при загрузке
|
||||
|
||||
// Восстанавливаем элементы пропуска
|
||||
container.innerHTML += '<button id="skipButton" class="skip-button" onclick="skipAd()">Пропустить рекламу</button>';
|
||||
container.innerHTML += '<div id="skipTimer" class="skip-timer">Пропустить через: <span id="skipTime">5</span>с</div>';
|
||||
|
||||
// Обновляем ссылки на элементы
|
||||
skipButton = document.getElementById('skipButton');
|
||||
skipTimer = document.getElementById('skipTimer');
|
||||
skipTimeSpan = document.getElementById('skipTime');
|
||||
|
||||
console.log('Skip elements restored for custom XML:', {
|
||||
skipButton: skipButton,
|
||||
skipTimer: skipTimer,
|
||||
skipTimeSpan: skipTimeSpan
|
||||
});
|
||||
|
||||
try {
|
||||
// Создаем Blob URL для пользовательского XML
|
||||
var blob = new Blob([xmlContent], {type: 'application/xml'});
|
||||
var url = URL.createObjectURL(blob);
|
||||
console.log('Custom XML blob URL created:', url);
|
||||
|
||||
player.load(url).then(function() {
|
||||
console.log('Custom XML ad loaded successfully');
|
||||
sendToFlutter('onAdLoaded');
|
||||
return player.startAd();
|
||||
}).catch(function(reason) {
|
||||
console.error('Failed to load custom ad:', reason);
|
||||
container.innerHTML = '<div class="error">Ошибка загрузки пользовательской рекламы: ' + reason.message + '</div>';
|
||||
sendToFlutter('onAdError', reason);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error creating blob URL for custom XML:', error);
|
||||
container.innerHTML = '<div class="error">Ошибка создания пользовательской рекламы: ' + error.message + '</div>';
|
||||
sendToFlutter('onAdError', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Функция для остановки рекламы
|
||||
window.stopAd = function() {
|
||||
console.log('Stopping ad');
|
||||
player.stopAd();
|
||||
};
|
||||
|
||||
// Функция для паузы/возобновления рекламы
|
||||
window.toggleAdPlayback = function() {
|
||||
if (player.isPlaying()) {
|
||||
player.pauseAd();
|
||||
} else {
|
||||
player.resumeAd();
|
||||
}
|
||||
};
|
||||
|
||||
// Обработчики всех событий
|
||||
[
|
||||
'AdLoaded',
|
||||
'AdStarted',
|
||||
'AdStopped',
|
||||
'AdSkipped',
|
||||
'AdSkippableStateChange',
|
||||
'AdSizeChange',
|
||||
'AdLinearChange',
|
||||
'AdDurationChange',
|
||||
'AdExpandedChange',
|
||||
'AdRemainingTimeChange',
|
||||
'AdVolumeChange',
|
||||
'AdImpression',
|
||||
'AdVideoStart',
|
||||
'AdVideoFirstQuartile',
|
||||
'AdVideoMidpoint',
|
||||
'AdVideoThirdQuartile',
|
||||
'AdVideoComplete',
|
||||
'AdClickThru',
|
||||
'AdInteraction',
|
||||
'AdUserAcceptInvitation',
|
||||
'AdUserMinimize',
|
||||
'AdUserClose',
|
||||
'AdPaused',
|
||||
'AdPlaying',
|
||||
'AdLog',
|
||||
'AdError'
|
||||
].forEach(function(type) {
|
||||
player.on(type, function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
console.log('EVENT: ' + type, args);
|
||||
|
||||
// Отправляем событие в Flutter
|
||||
var eventName = 'on' + type;
|
||||
sendToFlutter(eventName, args.length > 0 ? args[0] : null);
|
||||
|
||||
// Специальная обработка для завершения рекламы
|
||||
if (type === 'AdStopped') {
|
||||
sendToFlutter('onAdComplete');
|
||||
hideSkipElements();
|
||||
}
|
||||
|
||||
// Специальная обработка для пропуска рекламы
|
||||
if (type === 'AdSkipped') {
|
||||
sendToFlutter('onAdSkipped');
|
||||
hideSkipElements();
|
||||
}
|
||||
|
||||
// Специальная обработка для изменения состояния пропуска
|
||||
if (type === 'AdSkippableStateChange') {
|
||||
if (args.length > 0 && args[0]) {
|
||||
// Получаем skipoffset из VAST данных
|
||||
skipOffsetFromVast = getSkipOffsetFromVast();
|
||||
console.log('Ad is skippable, skip offset from VAST:', skipOffsetFromVast);
|
||||
showSkipTimer(); // Показываем таймер, если реклама стала пропускаемой
|
||||
} else {
|
||||
hideSkipElements(); // Скрываем, если реклама не пропускаемая
|
||||
}
|
||||
}
|
||||
|
||||
// Специальная обработка для начала рекламы
|
||||
if (type === 'AdStarted') {
|
||||
sendToFlutter('onAdStarted');
|
||||
// Проверяем, пропускаемая ли реклама
|
||||
if (player.isSkippable()) {
|
||||
skipOffsetFromVast = getSkipOffsetFromVast();
|
||||
console.log('Ad started and is skippable, skip offset:', skipOffsetFromVast);
|
||||
showSkipTimer();
|
||||
}
|
||||
}
|
||||
|
||||
// Специальная обработка для загрузки рекламы
|
||||
if (type === 'AdLoaded') {
|
||||
sendToFlutter('onAdLoaded');
|
||||
// Проверяем skipoffset сразу после загрузки
|
||||
setTimeout(function() {
|
||||
if (player.isSkippable()) {
|
||||
skipOffsetFromVast = getSkipOffsetFromVast();
|
||||
console.log('Ad loaded and is skippable, skip offset:', skipOffsetFromVast);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// Специальная обработка для кликов
|
||||
if (type === 'AdClickThru') {
|
||||
sendToFlutter('onAdClick');
|
||||
// Пытаемся открыть ссылку
|
||||
if (args.length > 0 && args[0]) {
|
||||
console.log('Opening click URL:', args[0]);
|
||||
try {
|
||||
window.open(args[0], '_blank');
|
||||
} catch (e) {
|
||||
console.error('Error opening click URL:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Загружаем рекламу по умолчанию
|
||||
loadVastAd('https://platform-staging.reelcontent.com/api/public/vast/2.0/tag?campaign=cam-e951792a909f17');
|
||||
|
||||
}(window.VASTPlayer));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
148
games/mnemo_cards_game_api/PROJECT_STRUCTURE.md
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
# 📦 Flutter WebView Bridge — структура проекта
|
||||
|
||||
Проект разделён на независимые пакеты (монорепозиторий с Melos), чтобы:
|
||||
|
||||
- отделить зависимости между `host`, `web` и `payloads`;
|
||||
- изолировать доступ к данным (web видит только нужное);
|
||||
- упростить масштабирование и тестирование.
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ Общая структура
|
||||
|
||||
```
|
||||
├── games/
|
||||
│ ├── bridge_core/ # Общие типы и сериализация
|
||||
│ ├── payloads_shared/ # Payload'ы, общие для всех
|
||||
│ ├── payloads_host/ # Только для host-приложения
|
||||
│ ├── payloads_app1/ # Только для web_app1
|
||||
│ ├── host_app/ # Flutter Host App (с WebView)
|
||||
│ ├── web_app1/ # Flutter Web-приложение 1
|
||||
├── melos.yaml # Конфигурация монорепозитория
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 Описание пакетов
|
||||
|
||||
### `bridge_core/`
|
||||
|
||||
Содержит:
|
||||
|
||||
- `BridgeMessage` — модель сообщения
|
||||
- `BridgePayload` — абстракция типа данных
|
||||
- `PayloadRegistry` — карта `"type"` → `fromJson`
|
||||
|
||||
Используется **всеми** остальными пакетами.
|
||||
|
||||
---
|
||||
|
||||
### `payloads_shared/`
|
||||
|
||||
Содержит payload'ы, используемые и в `host`, и в web-приложениях.
|
||||
Пример: `GetUserInfoPayload`, `PingPayload`.
|
||||
|
||||
Импортируется и в `host_app`, и в `web_app1`, `web_app2`.
|
||||
|
||||
---
|
||||
|
||||
### `payloads_host/`
|
||||
|
||||
Содержит payload'ы, специфичные для хост-приложения.
|
||||
Пример: `SecretAdminCommand`, `ShowNativeDialogPayload`.
|
||||
|
||||
Импортируется **только в `host_app`**.
|
||||
|
||||
---
|
||||
|
||||
### `payloads_app1/`
|
||||
|
||||
Содержит payload'ы, специфичные для web-приложения 1.
|
||||
Пример: `LoginRequestPayload`, `SubmitQuizPayload`.
|
||||
|
||||
Импортируется **только в `web_app1`** и `host_app`.
|
||||
|
||||
---
|
||||
|
||||
### `host_app/`
|
||||
|
||||
Flutter-приложение с WebView.
|
||||
|
||||
- Имеет доступ ко всем `payloads_*` пакетам
|
||||
- Обрабатывает все события
|
||||
- Реализует `BridgeWebViewController`
|
||||
|
||||
---
|
||||
|
||||
### `web_app1/`
|
||||
|
||||
Flutter Web-приложение, встроенное в WebView.
|
||||
|
||||
- Импортирует только нужные `payloads_*`
|
||||
- Регистрирует только свои payload'ы
|
||||
- Не видит лишнего
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Разделение доступа
|
||||
|
||||
| Пакет | Видит payloads_shared | Видит payloads_host | Видит payloads_app1 |
|
||||
|---------------|------------------------|----------------------|----------------------|
|
||||
| host_app | ✅ | ✅ | ✅ |
|
||||
| web_app1 | ✅ | ❌ | ✅ |
|
||||
| web_app2 | ✅ | ❌ | ❌ |
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Melos
|
||||
|
||||
Файл `melos.yaml` в корне:
|
||||
|
||||
```yaml
|
||||
name: flutter_webview_bridge_repo
|
||||
packages:
|
||||
- packages/**
|
||||
```
|
||||
|
||||
Запуск:
|
||||
```bash
|
||||
melos bootstrap
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📥 Регистрация payload'ов
|
||||
|
||||
Каждый payload-пакет содержит:
|
||||
|
||||
```dart
|
||||
void registerPayloads() {
|
||||
BridgePayload.register('type_name', (json) => MyPayload.fromJson(json));
|
||||
}
|
||||
```
|
||||
|
||||
В `main()` у приложения:
|
||||
|
||||
```dart
|
||||
void main() {
|
||||
registerPayloads();
|
||||
runApp(MyApp());
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📌 Пример использования
|
||||
|
||||
```dart
|
||||
// Web-приложение
|
||||
GetUserInfoPayload(fields: ['name']).toMessage().sendToHost();
|
||||
|
||||
// Хост-приложение
|
||||
hostBridge.registerHandler('get_user_info', (msg) {
|
||||
final payload = GetUserInfoPayload.fromJson(msg.data);
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
25
games/mnemo_cards_game_api/lib/src/app_binder.dart
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import 'package:mnemo_cards_game_api/mnemo_cards_game_api.dart';
|
||||
|
||||
import 'game_data.dart';
|
||||
|
||||
abstract class AppBinder<T extends GameData> {
|
||||
/// Initialize the JavaScript environment
|
||||
Future<void> init();
|
||||
|
||||
/// Dispose the JavaScript environment
|
||||
Future<void> dispose();
|
||||
|
||||
Future<GameEventResponse?> sendEvent(GameEvent event);
|
||||
|
||||
Future<T> get getGameData;
|
||||
|
||||
set gameData(T settings);
|
||||
|
||||
Stream<T> get gameDataStream;
|
||||
|
||||
set gameSettings(GameSettings settings);
|
||||
|
||||
Future<GameSettings> get getGameSettings;
|
||||
|
||||
Stream<GameSettings> get gameSettingsStream;
|
||||
}
|
||||
268
games/mnemo_cards_game_api/lib/src/app_binder_impl.dart
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
// import 'dart:async';
|
||||
// import 'dart:convert';
|
||||
// import 'dart:convert';
|
||||
// import 'dart:typed_data';
|
||||
// import 'dart:js_interop' as js;
|
||||
//
|
||||
// import 'package:mnemo_cards_game_api/mnemo_cards_game_api.dart';
|
||||
//
|
||||
// import 'app_binder.dart';
|
||||
//
|
||||
// class AppBinderImpl implements AppBinder {
|
||||
// final _messageHandlers = <String, Completer<dynamic>>{};
|
||||
// bool _musicEnabled = true;
|
||||
// bool _soundEnabled = true;
|
||||
// bool _isDarkMode = false;
|
||||
//
|
||||
// @override
|
||||
// void initializeJavaScript() {
|
||||
// print('[AppBinder] Initializing JavaScript environment');
|
||||
//
|
||||
// // Set up the message handler for responses from the host app
|
||||
// js.context['handleMessageFromHost'] = (String message) {
|
||||
// print('[AppBinder] Received message from host: $message');
|
||||
// try {
|
||||
// final data = jsonDecode(message);
|
||||
// final type = data['type'] as String;
|
||||
// print('[AppBinder] Message type: $type');
|
||||
//
|
||||
// final completer = _messageHandlers[type];
|
||||
// if (completer != null) {
|
||||
// print('[AppBinder] Found handler for message type: $type');
|
||||
// _messageHandlers.remove(type);
|
||||
// completer.complete(data);
|
||||
// } else {
|
||||
// print(
|
||||
// '[AppBinder] Warning: No handler found for message type: $type',
|
||||
// );
|
||||
// }
|
||||
// } catch (e) {
|
||||
// print('[AppBinder] Error handling message from host: $e');
|
||||
// print('[AppBinder] Message was: $message');
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// // Define the function that the host app will inject
|
||||
// if (js.context['sendMessageToHost'] == null) {
|
||||
// print('[AppBinder] Setting up default sendMessageToHost');
|
||||
// js.context['sendMessageToHost'] = (String message) {
|
||||
// print(
|
||||
// '[AppBinder] Warning: Using default sendMessageToHost implementation',
|
||||
// );
|
||||
// print('[AppBinder] Message would have been: $message');
|
||||
// };
|
||||
// } else {
|
||||
// print('[AppBinder] sendMessageToHost is already defined by host app');
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Future<dynamic> _sendMessage(String type, Map<String, dynamic> data) async {
|
||||
// print('[AppBinder] Sending message type: $type');
|
||||
// print('[AppBinder] Message data: $data');
|
||||
//
|
||||
// final completer = Completer<dynamic>();
|
||||
// _messageHandlers[type] = completer;
|
||||
//
|
||||
// final request = jsonEncode({'type': type, 'data': data});
|
||||
//
|
||||
// print('[AppBinder] Sending request to host: $request');
|
||||
//
|
||||
// // Send message to host app
|
||||
// js.context.callMethod('sendMessageToHost', [request]);
|
||||
//
|
||||
// print('[AppBinder] Waiting for response from host...');
|
||||
// final response = await completer.future;
|
||||
// print('[AppBinder] Received response: $response');
|
||||
//
|
||||
// return response;
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<void> playWord(String word, {String? lang}) async {
|
||||
// if (!_soundEnabled) {
|
||||
// print('[AppBinder] Sound is disabled, skipping word playback');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// print('[AppBinder] Playing word: $word, language: $lang');
|
||||
// try {
|
||||
// final Map<String, dynamic> args = {
|
||||
// 'word': word,
|
||||
// if (lang != null) 'lang': lang,
|
||||
// };
|
||||
// await _sendMessage('playWord', args);
|
||||
// print('[AppBinder] Successfully played word: $word');
|
||||
// } catch (e) {
|
||||
// print('[AppBinder] Error playing word: $e');
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<Uint8List> loadFileBytes(String path) async {
|
||||
// print('[AppBinder] Loading file bytes from: $path');
|
||||
// try {
|
||||
// final result = await _sendMessage('loadFileBytes', {'path': path});
|
||||
//
|
||||
// if (result['error'] != null) {
|
||||
// print('[AppBinder] Error loading file bytes: ${result['error']}');
|
||||
// throw Exception(result['error']);
|
||||
// }
|
||||
//
|
||||
// final bytes = base64Decode(result['data']);
|
||||
// print('[AppBinder] Successfully loaded ${bytes.length} bytes');
|
||||
// return bytes;
|
||||
// } catch (e) {
|
||||
// print('[AppBinder] Error loading file bytes: $e');
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<String?> getCustomBackground(String word) async {
|
||||
// print('[AppBinder] Getting custom background for word: $word');
|
||||
// try {
|
||||
// final result = await _sendMessage('getCustomBackground', {'word': word});
|
||||
// final background = result['data'] as String?;
|
||||
// print('[AppBinder] Custom background result: $background');
|
||||
// return background;
|
||||
// } catch (e) {
|
||||
// print('[AppBinder] Error getting custom background: $e');
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<GameSettings> loadSettings() async {
|
||||
// print('[AppBinder] Loading settings');
|
||||
// try {
|
||||
// final result = await _sendMessage('loadSettings', {});
|
||||
//
|
||||
// if (result['error'] != null) {
|
||||
// print('[AppBinder] Error in settings response: ${result['error']}');
|
||||
// throw Exception(result['error']);
|
||||
// }
|
||||
//
|
||||
// final data = result['data'] as Map<String, dynamic>;
|
||||
// print('[AppBinder] Received settings: $data');
|
||||
//
|
||||
// // Update local states
|
||||
// _musicEnabled = data['musicEnabled'] ?? true;
|
||||
// _soundEnabled = data['soundEnabled'] ?? true;
|
||||
// _isDarkMode = data['isDarkMode'] ?? false;
|
||||
//
|
||||
// return GameSettings.fromJson(data);
|
||||
// } catch (e) {
|
||||
// print('[AppBinder] Error loading settings: $e');
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<List<WordWithTranslation>> loadWordsWithTranslations() async {
|
||||
// print('[AppBinder] Loading words with translations');
|
||||
// try {
|
||||
// final result = await _sendMessage('loadWordsWithTranslations', {});
|
||||
//
|
||||
// if (result['error'] != null) {
|
||||
// print('[AppBinder] Error in words response: ${result['error']}');
|
||||
// throw Exception(result['error']);
|
||||
// }
|
||||
//
|
||||
// final List<dynamic> data = result['data'] as List<dynamic>;
|
||||
// print('[AppBinder] Received ${data.length} words');
|
||||
// final words = data
|
||||
// .map(
|
||||
// (item) =>
|
||||
// WordWithTranslation.fromJson(item as Map<String, dynamic>),
|
||||
// )
|
||||
// .toList();
|
||||
// print('[AppBinder] Words loaded: ${words.map((w) => w.word).join(', ')}');
|
||||
// return words;
|
||||
// } catch (e) {
|
||||
// print('[AppBinder] Error loading words with translations: $e');
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<void> setMusicEnabled(bool enabled) async {
|
||||
// print('[AppBinder] Setting music enabled: $enabled');
|
||||
// try {
|
||||
// await _sendMessage('setMusicEnabled', {'enabled': enabled});
|
||||
// _musicEnabled = enabled;
|
||||
// print('[AppBinder] Successfully set music enabled: $enabled');
|
||||
// } catch (e) {
|
||||
// print('[AppBinder] Error setting music enabled: $e');
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<void> setSoundEnabled(bool enabled) async {
|
||||
// print('[AppBinder] Setting sound enabled: $enabled');
|
||||
// try {
|
||||
// await _sendMessage('setSoundEnabled', {'enabled': enabled});
|
||||
// _soundEnabled = enabled;
|
||||
// print('[AppBinder] Successfully set sound enabled: $enabled');
|
||||
// } catch (e) {
|
||||
// print('[AppBinder] Error setting sound enabled: $e');
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<bool> isMusicEnabled() async {
|
||||
// print('[AppBinder] Getting music enabled state');
|
||||
// try {
|
||||
// final result = await _sendMessage('getMusicEnabled', {});
|
||||
// _musicEnabled = result['data']['enabled'] as bool;
|
||||
// print('[AppBinder] Music enabled: $_musicEnabled');
|
||||
// return _musicEnabled;
|
||||
// } catch (e) {
|
||||
// print('[AppBinder] Error getting music enabled state: $e');
|
||||
// return _musicEnabled; // Return cached value on error
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<bool> isSoundEnabled() async {
|
||||
// print('[AppBinder] Getting sound enabled state');
|
||||
// try {
|
||||
// final result = await _sendMessage('getSoundEnabled', {});
|
||||
// _soundEnabled = result['data']['enabled'] as bool;
|
||||
// print('[AppBinder] Sound enabled: $_soundEnabled');
|
||||
// return _soundEnabled;
|
||||
// } catch (e) {
|
||||
// print('[AppBinder] Error getting sound enabled state: $e');
|
||||
// return _soundEnabled; // Return cached value on error
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<void> setDarkMode(bool enabled) async {
|
||||
// print('[AppBinder] Setting dark mode: $enabled');
|
||||
// try {
|
||||
// await _sendMessage('setDarkMode', {'enabled': enabled});
|
||||
// _isDarkMode = enabled;
|
||||
// print('[AppBinder] Successfully set dark mode: $enabled');
|
||||
// } catch (e) {
|
||||
// print('[AppBinder] Error setting dark mode: $e');
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// Future<bool> isDarkMode() async {
|
||||
// print('[AppBinder] Getting dark mode state');
|
||||
// try {
|
||||
// final result = await _sendMessage('getDarkMode', {});
|
||||
// _isDarkMode = result['data']['enabled'] as bool;
|
||||
// print('[AppBinder] Dark mode: $_isDarkMode');
|
||||
// return _isDarkMode;
|
||||
// } catch (e) {
|
||||
// print('[AppBinder] Error getting dark mode state: $e');
|
||||
// return _isDarkMode; // Return cached value on error
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import 'package:mnemo_cards_game_api/src/game_data.dart';
|
||||
|
||||
class FunnyLettersGameData implements GameData {
|
||||
|
||||
}
|
||||
1
games/mnemo_cards_game_api/lib/src/game_data.dart
Normal file
|
|
@ -0,0 +1 @@
|
|||
abstract class GameData {}
|
||||
154
games/mnemo_cards_game_api/lib/src/game_page.dart
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
import 'dart:developer';
|
||||
import 'package:flutter/material.dart';
|
||||
// import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
// import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
class WebViewPage extends StatefulWidget {
|
||||
final String url;
|
||||
final String? title;
|
||||
final String? returnUrl;
|
||||
final VoidCallback? onPop;
|
||||
final bool safeArea;
|
||||
final bool setupToken;
|
||||
|
||||
const WebViewPage({
|
||||
required this.url,
|
||||
this.onPop,
|
||||
this.returnUrl,
|
||||
this.title,
|
||||
this.safeArea = false,
|
||||
this.setupToken = false,
|
||||
});
|
||||
|
||||
@override
|
||||
State<WebViewPage> createState() => _WebViewPageState();
|
||||
}
|
||||
|
||||
class _WebViewPageState extends State<WebViewPage> with WidgetsBindingObserver {
|
||||
bool canPop = false;
|
||||
late final WebViewController controller;
|
||||
bool _isBlank = false;
|
||||
|
||||
void _onPop() {
|
||||
if (widget.onPop != null) {
|
||||
widget.onPop!();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
|
||||
controller = WebViewController()
|
||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||
..setBackgroundColor(Colors.white)
|
||||
..setNavigationDelegate(
|
||||
NavigationDelegate(
|
||||
onNavigationRequest: (r) {
|
||||
final u = Uri.parse(r.url);
|
||||
if (u.scheme != 'http' && u.scheme != 'https') {
|
||||
_handleDeeplink(u);
|
||||
return NavigationDecision.prevent;
|
||||
}
|
||||
return NavigationDecision.navigate;
|
||||
},
|
||||
onPageStarted: (u) async {
|
||||
// если вернулись на returnUrl
|
||||
if (widget.returnUrl != null && u.contains(widget.returnUrl!)) {
|
||||
_popAndClose();
|
||||
}
|
||||
// подставляем токен
|
||||
if (widget.setupToken) {
|
||||
final token = await _userToken();
|
||||
if (token != null) {
|
||||
final uri = Uri.parse(widget.url);
|
||||
final host = '${uri.scheme}://${uri.host}';
|
||||
controller.runJavaScript('''
|
||||
window.getUnityToken = ()=>'$token';
|
||||
window.unityData={targetUrl:"$host"};
|
||||
function ExitGame(){Flutter.postMessage('exitGame');}
|
||||
''');
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
..loadRequest(Uri.parse(widget.url));
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
super.didChangeAppLifecycleState(state);
|
||||
|
||||
if ((state == AppLifecycleState.paused || state == AppLifecycleState.inactive) && mounted) {
|
||||
// при уходе в фон — грузим пустую страницу, чтобы сразу остановить звук
|
||||
controller.loadRequest(Uri.parse('about:blank'));
|
||||
_isBlank = true;
|
||||
}
|
||||
|
||||
if (state == AppLifecycleState.resumed && mounted) {
|
||||
// при возврате — восстанавливаем исходный URL
|
||||
if (_isBlank) {
|
||||
controller.loadRequest(Uri.parse(widget.url));
|
||||
_isBlank = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> _userToken() async {}
|
||||
|
||||
Future<void> _handleDeeplink(Uri uri) async {}
|
||||
|
||||
Future<void> _popAndClose() async {
|
||||
if (!canPop) {
|
||||
setState(() => canPop = true);
|
||||
|
||||
// очищаем WebView
|
||||
await controller.loadRequest(Uri.parse('about:blank'));
|
||||
await Future.wait([
|
||||
controller.clearCache(),
|
||||
controller.clearLocalStorage(),
|
||||
controller.removeJavaScriptChannel('Flutter'),
|
||||
]);
|
||||
|
||||
_onPop();
|
||||
await Future.delayed(const Duration(milliseconds: 250));
|
||||
// AutoRouter.of(context).parent()?.maybePop(true);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// на всякий случай — "убиваем" WebView перед уничтожением
|
||||
controller.loadRequest(Uri.parse('about:blank'));
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PopScope(
|
||||
canPop: canPop,
|
||||
onPopInvokedWithResult: (didPop, _) async {
|
||||
if (!canPop) {
|
||||
setState(() => canPop = true);
|
||||
await controller.loadRequest(Uri.parse('about:blank'));
|
||||
_onPop();
|
||||
await Future.delayed(const Duration(milliseconds: 250));
|
||||
// AutoRouter.of(context).back();
|
||||
}
|
||||
},
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
body: SafeArea(
|
||||
top: widget.safeArea,
|
||||
bottom: widget.safeArea,
|
||||
child: WebViewWidget(controller: controller),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
37
games/mnemo_cards_game_api/lib/src/game_theme.dart
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class GameSettings {
|
||||
final bool musicEnabled;
|
||||
final bool soundEnabled;
|
||||
final GameThemeData themeData;
|
||||
|
||||
GameSettings({
|
||||
this.musicEnabled = true,
|
||||
this.soundEnabled = true,
|
||||
required this.themeData,
|
||||
});
|
||||
|
||||
factory GameSettings.fromJson(Map<String, dynamic> json) {
|
||||
return GameSettings(
|
||||
musicEnabled: json['musicEnabled'] ?? true,
|
||||
soundEnabled: json['soundEnabled'] ?? true,
|
||||
themeData: GameThemeData(
|
||||
brightness: json['isDarkMode'] == true
|
||||
? Brightness.dark
|
||||
: Brightness.light,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'musicEnabled': musicEnabled,
|
||||
'soundEnabled': soundEnabled,
|
||||
'isDarkMode': themeData.brightness == Brightness.dark,
|
||||
};
|
||||
}
|
||||
|
||||
class GameThemeData {
|
||||
final Brightness brightness;
|
||||
|
||||
const GameThemeData({required this.brightness});
|
||||
}
|
||||
20
games/mnemo_cards_game_api/lib/src/theme.dart
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:mnemo_cards_game_api/mnemo_cards_game_api.dart';
|
||||
|
||||
extension ThemeDataExtensions on GameThemeData {
|
||||
ThemeData toMaterialTheme() {
|
||||
return brightness == Brightness.light
|
||||
? ThemeData.light().copyWith(
|
||||
colorScheme: ColorScheme.fromSwatch(
|
||||
backgroundColor: Colors.white,
|
||||
brightness: Brightness.light,
|
||||
),
|
||||
)
|
||||
: ThemeData.dark().copyWith(
|
||||
colorScheme: ColorScheme.fromSwatch(
|
||||
backgroundColor: Colors.white,
|
||||
brightness: Brightness.light,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
16
games/mnemo_cards_web_bridge/lib/src/web_app_bridget.dart
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
abstract interface class WebAppBridget {
|
||||
/// Returns the current URL of the web application.
|
||||
String getCurrentUrl();
|
||||
|
||||
/// Navigates to the specified URL.
|
||||
void navigateTo(String url);
|
||||
|
||||
/// Reloads the current page.
|
||||
void reloadPage();
|
||||
|
||||
/// Returns the title of the current page.
|
||||
String getPageTitle();
|
||||
|
||||
/// Sets the title of the current page.
|
||||
void setPageTitle(String title);
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
import 'package:bridge_core/bridge_core.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:copy_with_extension/copy_with_extension.dart';
|
||||
|
||||
part 'user_cards_payload.g.dart';
|
||||
|
||||
@CopyWith()
|
||||
@JsonSerializable()
|
||||
class UserCardsRequestPayload extends BridgePayload {
|
||||
@JsonKey(name: 'pack_ids')
|
||||
final List<String>? packIds;
|
||||
@JsonKey(name: 'card_ids')
|
||||
final List<String>? cardIds;
|
||||
@JsonKey(name: 'original_words')
|
||||
final List<String>? originalWords;
|
||||
@JsonKey(name: 'translation_words')
|
||||
final List<String>? translationWords;
|
||||
|
||||
const UserCardsRequestPayload({
|
||||
this.packIds,
|
||||
this.cardIds,
|
||||
this.originalWords,
|
||||
this.translationWords,
|
||||
});
|
||||
|
||||
@override
|
||||
Map<String, Object?> toJson() => _$UserCardsRequestPayloadToJson(this);
|
||||
|
||||
@override
|
||||
String get type => 'user_cards_request_payload';
|
||||
}
|
||||
|
||||
@CopyWith()
|
||||
@JsonSerializable()
|
||||
class UserCardsPayload extends BridgePayload {
|
||||
@JsonKey(name: 'cards')
|
||||
final List<GameCard> gameCards;
|
||||
|
||||
UserCardsPayload({required this.gameCards});
|
||||
|
||||
@override
|
||||
Map<String, Object?> toJson() => _$UserCardsPayloadToJson(this);
|
||||
|
||||
@override
|
||||
String get type => 'user_cards_payload';
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
@CopyWith()
|
||||
class GameCard {
|
||||
final int id;
|
||||
final String? image;
|
||||
final String? mnemo;
|
||||
final String? original;
|
||||
final String? translation;
|
||||
final String? transcription;
|
||||
final String? imageBack;
|
||||
final String? transcriptionMnemo;
|
||||
final String? back;
|
||||
|
||||
const GameCard({
|
||||
required this.id,
|
||||
required this.mnemo,
|
||||
required this.original,
|
||||
required this.translation,
|
||||
required this.transcription,
|
||||
this.transcriptionMnemo,
|
||||
this.image,
|
||||
this.imageBack,
|
||||
this.back,
|
||||
});
|
||||
|
||||
factory GameCard.fromJson(Map<String, dynamic> json) =>
|
||||
_$GameCardFromJson(json);
|
||||
|
||||
Map<String, Object?> toJson() => _$GameCardToJson(this);
|
||||
}
|
||||
BIN
icons/back.png
|
Before Width: | Height: | Size: 21 KiB |
BIN
icons/cards.png
|
Before Width: | Height: | Size: 1.4 KiB |
BIN
icons/chat.png
|
Before Width: | Height: | Size: 11 KiB |
BIN
icons/clock.png
|
Before Width: | Height: | Size: 729 B |
BIN
icons/crown.png
|
Before Width: | Height: | Size: 351 B |
BIN
icons/down.png
|
Before Width: | Height: | Size: 976 B |
BIN
icons/exit.png
|
Before Width: | Height: | Size: 703 B |
BIN
icons/gift.png
|
Before Width: | Height: | Size: 684 B |
BIN
icons/google.png
|
Before Width: | Height: | Size: 4.7 KiB |
BIN
icons/heart.png
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 913 B |
BIN
icons/mic_on.png
|
Before Width: | Height: | Size: 771 B |
BIN
icons/next.png
|
Before Width: | Height: | Size: 874 B |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 847 B |
|
Before Width: | Height: | Size: 5.5 KiB |
BIN
icons/skull.png
|
Before Width: | Height: | Size: 563 B |
|
Before Width: | Height: | Size: 312 B |
|
Before Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
BIN
icons/tg.png
|
Before Width: | Height: | Size: 3 KiB |
BIN
icons/view.png
|
Before Width: | Height: | Size: 9 KiB |
|
|
@ -1,2 +0,0 @@
|
|||
dart run flutter_native_splash:create
|
||||
dart run flutter_launcher_icons
|
||||
34
ios/.gitignore
vendored
|
|
@ -1,34 +0,0 @@
|
|||
**/dgph
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.moved-aside
|
||||
*.pbxuser
|
||||
*.perspectivev3
|
||||
**/*sync/
|
||||
.sconsign.dblite
|
||||
.tags*
|
||||
**/.vagrant/
|
||||
**/DerivedData/
|
||||
Icon?
|
||||
**/Pods/
|
||||
**/.symlinks/
|
||||
profile
|
||||
xcuserdata
|
||||
**/.generated/
|
||||
Flutter/App.framework
|
||||
Flutter/Flutter.framework
|
||||
Flutter/Flutter.podspec
|
||||
Flutter/Generated.xcconfig
|
||||
Flutter/ephemeral/
|
||||
Flutter/app.flx
|
||||
Flutter/app.zip
|
||||
Flutter/flutter_assets/
|
||||
Flutter/flutter_export_environment.sh
|
||||
ServiceDefinitions.json
|
||||
Runner/GeneratedPluginRegistrant.*
|
||||
|
||||
# Exceptions to above rules.
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.pbxuser
|
||||
!default.perspectivev3
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>App</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>io.flutter.flutter.app</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>App</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>14.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
49
ios/Podfile
|
|
@ -1,49 +0,0 @@
|
|||
# source 'https://github.com/CocoaPods/Specs.git'
|
||||
# source 'https://git.yoomoney.ru/scm/sdk/cocoa-pod-specs.git'
|
||||
|
||||
|
||||
# Uncomment this line to define a global platform for your project
|
||||
platform :ios, '14.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks! :linkage => :static
|
||||
# use_frameworks!
|
||||
use_modular_headers!
|
||||
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
end
|
||||
end
|
||||
1503
ios/Podfile.lock
|
|
@ -1,766 +0,0 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
88925E0304DA934B99CF07B5 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 039AEB256EC09C6DAD0D33F6 /* GoogleService-Info.plist */; };
|
||||
92F786B29EF12520764C9B34 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88D363FEAADB3317B3E14A0A /* Pods_Runner.framework */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
CF53E9FF8298D562D675E324 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F30B1603BBE3F803AFE2385E /* Pods_RunnerTests.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
||||
remoteInfo = Runner;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
039AEB256EC09C6DAD0D33F6 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
4CC79C7D41E157D878D889F0 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
5B971DEAC48A015D192A8EAB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
5DA2E070BDB961F389CD961D /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
5EFDFD0076C43FC4B256A2F9 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
88D363FEAADB3317B3E14A0A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D56245B45AA4EC506A74FF4E /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
F30B1603BBE3F803AFE2385E /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F34F38B9F662A96F77B6E782 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
7F8493084A5D32479BB9EA15 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CF53E9FF8298D562D675E324 /* Pods_RunnerTests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
92F786B29EF12520764C9B34 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */,
|
||||
);
|
||||
path = RunnerTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
70EAEEDC0F0D76C181949289 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
88D363FEAADB3317B3E14A0A /* Pods_Runner.framework */,
|
||||
F30B1603BBE3F803AFE2385E /* Pods_RunnerTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||
);
|
||||
name = Flutter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146E51CF9000F007C117D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
9BC5FF8B20D1CEE670C66ACD /* Pods */,
|
||||
70EAEEDC0F0D76C181949289 /* Frameworks */,
|
||||
039AEB256EC09C6DAD0D33F6 /* GoogleService-Info.plist */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146EF1CF9000F007C117D /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
97C147021CF9000F007C117D /* Info.plist */,
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||
);
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9BC5FF8B20D1CEE670C66ACD /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CC79C7D41E157D878D889F0 /* Pods-Runner.debug.xcconfig */,
|
||||
5B971DEAC48A015D192A8EAB /* Pods-Runner.release.xcconfig */,
|
||||
5DA2E070BDB961F389CD961D /* Pods-Runner.profile.xcconfig */,
|
||||
5EFDFD0076C43FC4B256A2F9 /* Pods-RunnerTests.debug.xcconfig */,
|
||||
F34F38B9F662A96F77B6E782 /* Pods-RunnerTests.release.xcconfig */,
|
||||
D56245B45AA4EC506A74FF4E /* Pods-RunnerTests.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
331C8080294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
FD56395D2DB589B058B3AF52 /* [CP] Check Pods Manifest.lock */,
|
||||
331C807D294A63A400263BE5 /* Sources */,
|
||||
331C807F294A63A400263BE5 /* Resources */,
|
||||
7F8493084A5D32479BB9EA15 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */,
|
||||
);
|
||||
name = RunnerTests;
|
||||
productName = RunnerTests;
|
||||
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
11939B8737D0761B1D52BA09 /* [CP] Check Pods Manifest.lock */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
10510DEBDDA8DED725BA2250 /* [CP] Copy Pods Resources */,
|
||||
EAA1E3F7E6B26606E42D1048 /* [CP] Embed Pods Frameworks */,
|
||||
8D11678BA08A0DD0DA55F454 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Runner;
|
||||
productName = Runner;
|
||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1510;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
331C8080294A63A400263BE5 = {
|
||||
CreatedOnToolsVersion = 14.0;
|
||||
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||
};
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 1100;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 97C146E51CF9000F007C117D;
|
||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
331C807F294A63A400263BE5 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
88925E0304DA934B99CF07B5 /* GoogleService-Info.plist in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
10510DEBDDA8DED725BA2250 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
11939B8737D0761B1D52BA09 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
8D11678BA08A0DD0DA55F454 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "FlutterFire: \"flutterfire upload-crashlytics-symbols\"";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\n#!/bin/bash\nPATH=${PATH}:$FLUTTER_ROOT/bin:$HOME/.pub-cache/bin\nflutterfire upload-crashlytics-symbols --upload-symbols-script-path=$PODS_ROOT/FirebaseCrashlytics/upload-symbols --platform=ios --apple-project-path=${SRCROOT} --env-platform-name=${PLATFORM_NAME} --env-configuration=${CONFIGURATION} --env-project-dir=${PROJECT_DIR} --env-built-products-dir=${BUILT_PRODUCTS_DIR} --env-dwarf-dsym-folder-path=${DWARF_DSYM_FOLDER_PATH} --env-dwarf-dsym-file-name=${DWARF_DSYM_FILE_NAME} --env-infoplist-path=${INFOPLIST_PATH} --default-config=default\n";
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run Script";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
EAA1E3F7E6B26606E42D1048 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
FD56395D2DB589B058B3AF52 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
331C807D294A63A400263BE5 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C146FB1CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C147001CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 6ZNY923QXG;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
331C8088294A63A400263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 5EFDFD0076C43FC4B256A2F9 /* Pods-RunnerTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
331C8089294A63A400263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = F34F38B9F662A96F77B6E782 /* Pods-RunnerTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
331C808A294A63A400263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D56245B45AA4EC506A74FF4E /* Pods-RunnerTests.profile.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
97C147031CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147041CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
97C147061CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 6ZNY923QXG;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147071CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 6ZNY923QXG;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
331C8088294A63A400263BE5 /* Debug */,
|
||||
331C8089294A63A400263BE5 /* Release */,
|
||||
331C808A294A63A400263BE5 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
97C147031CF9000F007C117D /* Debug */,
|
||||
97C147041CF9000F007C117D /* Release */,
|
||||
249021D3217E4FDB00AE95B9 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
97C147061CF9000F007C117D /* Debug */,
|
||||
97C147071CF9000F007C117D /* Release */,
|
||||
249021D4217E4FDB00AE95B9 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||