29 Commits

Author SHA1 Message Date
3a74b8017d Scooter order payment screen fix 2026-09-15 21:28:33 +03:00
153a763b6f Registration pipeline chenged - fill profile step added. Order payment fixed 2026-09-14 19:20:31 +03:00
7460408784 Finish screen - attention message added 2026-09-14 08:42:25 +03:00
5f57af2ad2 bug fixes 2026-09-04 13:41:57 +03:00
cf5b56e365 Tariff subsriptionId fix 2026-08-31 10:37:08 +03:00
b0c9f6dc17 fix qr 2026-08-31 09:57:40 +03:00
ece8e7ba79 bug fixes 2026-08-31 09:53:29 +03:00
02b3e5caa8 Tariff description fix, iOS payment card binding fix 2026-08-31 09:18:33 +03:00
a556dc5736 bug fixes 2026-08-29 00:00:09 +03:00
6513a004d9 fix profile 2026-08-18 15:09:53 +03:00
80a95ece5b fix to prod 2026-08-14 13:47:11 +03:00
f53fea576e add page company detail 2026-08-13 09:34:06 +03:00
182be1049b some fix
# Conflicts:
#	lib/presentation/navigation/app_router.dart
#	pubspec.yaml
2026-08-11 00:23:16 +03:00
c9b8d143d1 fixing the app launch bug 2026-07-27 11:06:04 +03:00
d5f70ee9c4 change package name 2026-07-19 20:27:26 +03:00
99d2875b56 Merge pull request 'map fix' (#8) from fix/ios-fix into main
Reviewed-on: #8
2026-07-16 11:16:14 +00:00
46cd22c287 fix merge conflict 2026-07-16 14:14:22 +03:00
0a6c40181a Merge pull request 'add test block' (#7) from fix/bug-fix into main
Reviewed-on: #7
2026-07-16 07:26:56 +00:00
fcb23e0d5f fix merge conflict 2026-07-16 10:15:10 +03:00
7a2c214ff5 map fix 2026-07-15 22:58:33 +03:00
419b54d5dd Merge pull request 'fix payment card change. fix adding a new payment card' (#6) from fix/bug-fix into main
Reviewed-on: #6
2026-07-13 12:47:55 +00:00
4a919a5bcc Merge pull request 'fix add new card in bottomsheet' (#5) from fix/bug-fix into main
Reviewed-on: #5
2026-07-13 08:50:59 +00:00
902c6d27a4 Merge pull request 'fix/bug-fix' (#4) from fix/bug-fix into main
Reviewed-on: #4
2026-07-12 22:53:19 +00:00
939b5be7d8 Merge pull request 'fix/ios-launch' (#3) from fix/ios-launch into main
Reviewed-on: #3
2026-06-01 15:02:16 +00:00
10c21e4ae3 resolved merge conflicts 2026-06-01 18:00:44 +03:00
406b2bc2dc Merge pull request 'fix/bug-fix' (#1) from fix/bug-fix into main
Reviewed-on: #1
2026-06-01 14:29:39 +00:00
bb49bbd0f7 docs(ios): update README for simulator setup and build instructions
- Translated and reorganized instructions for running the app on the iOS simulator.
- Added specific commands for terminal usage and emphasized the importance of executing commands from the correct project directory.
- Removed outdated sections and streamlined the content for clarity and relevance.

This update enhances the documentation for developers working with the iOS simulator.
2026-05-25 15:33:37 +03:00
7779803ccc chore: update dependencies and configurations for iOS build
- Updated mobile_scanner dependency version to 7.0.0 in pubspec.yaml.
- Adjusted versions of several packages in pubspec.lock.
- Added exclusion of arm64 architecture for iOS simulator in Podfile and xcconfig files to support Apple Silicon.
- Cleaned up Podfile.lock by removing unused dependencies.

This update ensures compatibility with the latest mobile_scanner and improves build stability on M1/M4 devices.
2026-05-25 15:23:13 +03:00
713cc2520b fix(ios): запуск на iOS — MapKit, ключ из xcconfig, CocoaPods
- AppDelegate: YMKMapKit до super, регистрация плагинов по шаблону Flutter 3.41
- Info.plist: YandexMapKitApiKey из $(YANDEX_MAPKIT_API_KEY)
- Debug/Release/Profile.xcconfig: ключ, include Pods и опциональный Secrets
- Podfile, workspace, pbxproj; .gitignore для Secrets.xcconfig, пример Secrets
- ios/README.md

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 10:32:18 +03:00
375 changed files with 27022 additions and 23566 deletions

View File

@@ -15,7 +15,7 @@ plugins {
} }
android { android {
namespace = "com.sparkit.be_happy" namespace = "com.behappybel.behappy"
compileSdk = flutter.compileSdkVersion compileSdk = flutter.compileSdkVersion
ndkVersion = "27.0.12077973" ndkVersion = "27.0.12077973"
@@ -44,7 +44,7 @@ android {
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.sparkit.behappy" applicationId = "com.behappybel.behappy"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config. // For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = 26 minSdk = 26

View File

@@ -26,7 +26,7 @@
<meta-data <meta-data
android:name="com.yandex.runtime.API_KEY" android:name="com.yandex.runtime.API_KEY"
android:value="a0ef1404-2650-4f28-9891-c965ecc09174" /> android:value="45fe500d-b549-4444-9e4b-3b2acd78ee2c" />
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

View File

@@ -1,4 +1,4 @@
package com.sparkit.be_happy package com.behappybel.behappy
import android.os.Bundle import android.os.Bundle
import com.yandex.mapkit.MapKitFactory import com.yandex.mapkit.MapKitFactory
@@ -6,7 +6,7 @@ import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity() { class MainActivity : FlutterActivity() {
override protected fun onCreate(savedInstanceState: Bundle?) { override protected fun onCreate(savedInstanceState: Bundle?) {
MapKitFactory.setApiKey("a0ef1404-2650-4f28-9891-c965ecc09174") MapKitFactory.setApiKey("45fe500d-b549-4444-9e4b-3b2acd78ee2c")
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

View File

@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" /> <item>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
<!-- You can insert your own image assets here --> </item>
<!-- <item> <item>
<bitmap <bitmap android:gravity="center" android:src="@drawable/splash"/>
android:gravity="center" </item>
android:src="@mipmap/launch_image" />
</item> -->
</layer-list> </layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

View File

@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" /> <item>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
<!-- You can insert your own image assets here --> </item>
<!-- <item> <item>
<bitmap <bitmap android:gravity="center" android:src="@drawable/splash"/>
android:gravity="center" </item>
android:src="@mipmap/launch_image" />
</item> -->
</layer-list> </layer-list>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,19 @@
<?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">
<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>

View File

@@ -5,6 +5,10 @@
<!-- Show a splash screen on the activity. Automatically removed when <!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame --> the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <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> </style>
<!-- Theme applied to the Android Window as soon as the process has started. <!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your This theme determines the color of the Android Window while your

View File

@@ -0,0 +1,19 @@
<?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>
</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>

View File

@@ -5,6 +5,10 @@
<!-- Show a splash screen on the activity. Automatically removed when <!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame --> the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <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> </style>
<!-- Theme applied to the Android Window as soon as the process has started. <!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your This theme determines the color of the Android Window while your

View File

@@ -4,5 +4,6 @@ android.enableJetifier=true
yandexMapkit.variant=full yandexMapkit.variant=full
# This builtInKotlin flag was added automatically by Flutter migrator # This builtInKotlin flag was added automatically by Flutter migrator
android.builtInKotlin=false android.builtInKotlin=false
kotlin.incremental=false
# This newDsl flag was added automatically by Flutter migrator # This newDsl flag was added automatically by Flutter migrator
android.newDsl=false android.newDsl=false

BIN
assets/icons/fine.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/payment_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
assets/rules_alpha.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
assets/rules_apple_pay.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
assets/rules_belcard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
assets/rules_mastercard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
assets/rules_visa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
assets/tech_works.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>MinimumOSVersion</key>
<string>13.0</string>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>en</string> <string>en</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
@@ -20,7 +22,5 @@
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict> </dict>
</plist> </plist>

View File

@@ -1 +1,6 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"
#include? "Secrets.xcconfig"
YANDEX_MAPKIT_API_KEY=45fe500d-b549-4444-9e4b-3b2acd78ee2c
// Переопределение Pods/ML Kit: arm64 для симулятора на Apple Silicon (M1/M4)
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386

View File

@@ -0,0 +1,5 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"
#include "Generated.xcconfig"
#include? "Secrets.xcconfig"
YANDEX_MAPKIT_API_KEY=45fe500d-b549-4444-9e4b-3b2acd78ee2c
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386

View File

@@ -1 +1,5 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"
#include? "Secrets.xcconfig"
YANDEX_MAPKIT_API_KEY=45fe500d-b549-4444-9e4b-3b2acd78ee2c
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386

View File

@@ -0,0 +1,2 @@
// Локальные переопределения (опционально). Не задавайте YANDEX_MAPKIT_API_KEY плейсхолдером —
// рабочий ключ задаётся в конце Debug/Release/Profile.xcconfig после этого include.

View File

@@ -0,0 +1,3 @@
// Скопируй в ios/Flutter/Secrets.xcconfig (файл в .gitignore) для своих локальных xcconfig-переменных.
// Ключ MapKit задаётся в конце Debug/Release/Profile.xcconfig — не подставляйте туда тестовый плейсхолдер вместо реального ключа.
// https://developer.tech.yandex.ru/

50
ios/Podfile Normal file
View File

@@ -0,0 +1,50 @@
# image_picker_ios и др. требуют минимум iOS 13
platform :ios, '15.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
ENV['YANDEX_MAPKIT_VARIANT'] = 'full'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
# ML Kit исключает arm64 для симулятора → сборка только x86_64.
# На M1 это ещё могло работать через Rosetta; на M4 симулятор только arm64.
config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'i386'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
end
end
end

80
ios/Podfile.lock Normal file
View File

@@ -0,0 +1,80 @@
PODS:
- device_info_plus (0.0.1):
- Flutter
- Flutter (1.0.0)
- flutter_native_splash (2.4.3):
- Flutter
- flutter_secure_storage (6.0.0):
- Flutter
- geolocator_apple (1.2.0):
- Flutter
- FlutterMacOS
- image_picker_ios (0.0.1):
- Flutter
- mobile_scanner (7.0.0):
- Flutter
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- url_launcher_ios (0.0.1):
- Flutter
- yandex_mapkit (0.0.1):
- Flutter
- YandexMapsMobile (= 4.22.0-full)
- YandexMapsMobile (4.22.0-full)
DEPENDENCIES:
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- Flutter (from `Flutter`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- yandex_mapkit (from `.symlinks/plugins/yandex_mapkit/ios`)
SPEC REPOS:
trunk:
- YandexMapsMobile
EXTERNAL SOURCES:
device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios"
Flutter:
:path: Flutter
flutter_native_splash:
:path: ".symlinks/plugins/flutter_native_splash/ios"
flutter_secure_storage:
:path: ".symlinks/plugins/flutter_secure_storage/ios"
geolocator_apple:
:path: ".symlinks/plugins/geolocator_apple/darwin"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
mobile_scanner:
:path: ".symlinks/plugins/mobile_scanner/darwin"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
yandex_mapkit:
:path: ".symlinks/plugins/yandex_mapkit/ios"
SPEC CHECKSUMS:
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
yandex_mapkit: b0468cf6fdc2e5ef315e08c081cb48763db1edee
YandexMapsMobile: 27e6e45425bb61f0be2dbc2bf02d4e64926691a9
PODFILE CHECKSUM: 4db91eb18e4c468b9b75ce0a1fbe33194b57f06a
COCOAPODS: 1.16.2

23
ios/README.md Normal file
View File

@@ -0,0 +1,23 @@
# Запуск на симуляторе (Mac)
**Терминал** (⌘ + `):
```bash
cd /Users/commercesparkit.by/Desktop/projekt/be_happy_public
export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
open -a Simulator
flutter run
```
Первый раз или после обновления кода:
```bash
cd /Users/commercesparkit.by/Desktop/projekt/be_happy_public
export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
flutter pub get
cd ios && pod install && cd ..
open -a Simulator
flutter run
```
Важно: команды только из папки `be_happy_public`, не из `~`.

View File

@@ -10,7 +10,9 @@
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
719658A7EA74BCF79744189C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 815E41E9A67B82F3B5893FB0 /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
947230899A63DCC5FC354559 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A5825CAAC7BEAFA8756F6D22 /* Pods_RunnerTests.framework */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
@@ -40,28 +42,46 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
12F1F4F8ABC8CE708CB9918F /* 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>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; 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>"; }; 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>"; }; 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; }; 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>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
4AADFAE03DF1A02E1E799949 /* 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>"; };
53B78B2283B7ADCE0208F756 /* 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>"; };
673086666704B99027FC010B /* 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>"; };
6EC6FEDB5882EB1ECF391D95 /* 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>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; 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>"; }; 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>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFC7F9B8515A109C72DDF1B /* 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>"; };
815E41E9A67B82F3B5893FB0 /* 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>"; }; 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>"; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEB41CF90195004384FC /* Profile.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Profile.xcconfig; path = Flutter/Profile.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A5825CAAC7BEAFA8756F6D22 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
83F4E53737A5B4793588BFEB /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
947230899A63DCC5FC354559 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = { 97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
719658A7EA74BCF79744189C /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -76,12 +96,22 @@
path = RunnerTests; path = RunnerTests;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
4E47A3B8F8440AE11EF826D6 /* Frameworks */ = {
isa = PBXGroup;
children = (
815E41E9A67B82F3B5893FB0 /* Pods_Runner.framework */,
A5825CAAC7BEAFA8756F6D22 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = { 9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */, 9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB41CF90195004384FC /* Profile.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */,
); );
name = Flutter; name = Flutter;
@@ -94,6 +124,8 @@
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */, 331C8082294A63A400263BE5 /* RunnerTests */,
BBAC3160211F77BA6C1CDBEB /* Pods */,
4E47A3B8F8440AE11EF826D6 /* Frameworks */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@@ -121,6 +153,19 @@
path = Runner; path = Runner;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
BBAC3160211F77BA6C1CDBEB /* Pods */ = {
isa = PBXGroup;
children = (
4AADFAE03DF1A02E1E799949 /* Pods-Runner.debug.xcconfig */,
673086666704B99027FC010B /* Pods-Runner.release.xcconfig */,
53B78B2283B7ADCE0208F756 /* Pods-Runner.profile.xcconfig */,
7AFC7F9B8515A109C72DDF1B /* Pods-RunnerTests.debug.xcconfig */,
12F1F4F8ABC8CE708CB9918F /* Pods-RunnerTests.release.xcconfig */,
6EC6FEDB5882EB1ECF391D95 /* Pods-RunnerTests.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@@ -128,8 +173,10 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = ( buildPhases = (
8320BCAEA155F95875F06656 /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */, 331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */, 331C807F294A63A400263BE5 /* Resources */,
83F4E53737A5B4793588BFEB /* Frameworks */,
); );
buildRules = ( buildRules = (
); );
@@ -145,12 +192,15 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = ( buildPhases = (
C59C8F9337F753AC74343087 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */, 9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */, 97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */, 97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
FB90C79E7B88832806AD3371 /* [CP] Embed Pods Frameworks */,
81264E30AB9A7C4C10AB44BA /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@@ -238,6 +288,45 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
}; };
81264E30AB9A7C4C10AB44BA /* [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;
};
8320BCAEA155F95875F06656 /* [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;
};
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
@@ -253,6 +342,45 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
}; };
C59C8F9337F753AC74343087 /* [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;
};
FB90C79E7B88832806AD3371 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@@ -346,30 +474,34 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
name = Profile; name = Profile;
}; };
249021D4217E4FDB00AE95B9 /* Profile */ = { 249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; baseConfigurationReference = 9740EEB41CF90195004384FC /* Profile.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = J463CU8H5F;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.sparkit.beHappy; PRODUCT_BUNDLE_IDENTIFIER = com.behappybel.behappy;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
@@ -378,13 +510,14 @@
}; };
331C8088294A63A400263BE5 /* Debug */ = { 331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 7AFC7F9B8515A109C72DDF1B /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.sparkit.beHappy.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = com.behappybel.behappy.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -395,13 +528,14 @@
}; };
331C8089294A63A400263BE5 /* Release */ = { 331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 12F1F4F8ABC8CE708CB9918F /* Pods-RunnerTests.release.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.sparkit.beHappy.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = com.behappybel.behappy.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -410,13 +544,14 @@
}; };
331C808A294A63A400263BE5 /* Profile */ = { 331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 6EC6FEDB5882EB1ECF391D95 /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.sparkit.beHappy.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = com.behappybel.behappy.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -472,11 +607,11 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1";
}; };
name = Debug; name = Debug;
}; };
@@ -523,13 +658,13 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule; SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
name = Release; name = Release;
@@ -540,15 +675,19 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = J463CU8H5F;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.sparkit.beHappy; PRODUCT_BUNDLE_IDENTIFIER = com.behappybel.behappy;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@@ -562,15 +701,19 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = J463CU8H5F;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.sparkit.beHappy; PRODUCT_BUNDLE_IDENTIFIER = com.behappybel.behappy;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";

View File

@@ -4,4 +4,7 @@
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "group:Runner.xcodeproj">
</FileRef> </FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace> </Workspace>

View File

@@ -1,13 +1,29 @@
import Flutter import Flutter
import UIKit import UIKit
import YandexMapsMobile
@main @main
@objc class AppDelegate: FlutterAppDelegate { @objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
override func application( override func application(
_ application: UIApplication, _ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
GeneratedPluginRegistrant.register(with: self) let apiKey =
(Bundle.main.object(forInfoDictionaryKey: "YandexMapKitApiKey") as? String ?? "")
.trimmingCharacters(in: .whitespacesAndNewlines)
#if DEBUG
if apiKey.isEmpty || apiKey.contains("$(") {
assertionFailure(
"YandexMapKitApiKey пустой или не подставился из xcconfig — проверь YANDEX_MAPKIT_API_KEY в ios/Flutter/*.xcconfig"
)
}
#endif
YMKMapKit.setLocale(Locale.current.identifier)
YMKMapKit.setApiKey(apiKey)
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
}
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 351 KiB

After

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 986 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "background.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

View File

@@ -1,23 +1,23 @@
{ {
"images" : [ "images" : [
{ {
"idiom" : "universal",
"filename" : "LaunchImage.png", "filename" : "LaunchImage.png",
"idiom" : "universal",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"idiom" : "universal",
"filename" : "LaunchImage@2x.png", "filename" : "LaunchImage@2x.png",
"idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"idiom" : "universal",
"filename" : "LaunchImage@3x.png", "filename" : "LaunchImage@3x.png",
"idiom" : "universal",
"scale" : "3x" "scale" : "3x"
} }
], ],
"info" : { "info" : {
"version" : 1, "author" : "xcode",
"author" : "xcode" "version" : 1
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -16,13 +16,19 @@
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="LaunchBackground" translatesAutoresizingMaskIntoConstraints="NO" id="tWc-Dq-wcI"/>
</imageView> <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"></imageView>
</subviews> </subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/> <constraint firstItem="YRO-k0-Ey4" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="3T2-ad-Qdv"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/> <constraint firstItem="tWc-Dq-wcI" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="RPx-PI-7Xg"/>
<constraint firstItem="tWc-Dq-wcI" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="SdS-ul-q2q"/>
<constraint firstAttribute="trailing" secondItem="tWc-Dq-wcI" secondAttribute="trailing" id="Swv-Gf-Rwn"/>
<constraint firstAttribute="trailing" secondItem="YRO-k0-Ey4" secondAttribute="trailing" id="TQA-XW-tRk"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="duK-uY-Gun"/>
<constraint firstItem="tWc-Dq-wcI" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="kV7-tw-vXt"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="xPn-NY-SIU"/>
</constraints> </constraints>
</view> </view>
</viewController> </viewController>
@@ -32,6 +38,7 @@
</scene> </scene>
</scenes> </scenes>
<resources> <resources>
<image name="LaunchImage" width="168" height="185"/> <image name="LaunchImage" width="130" height="130"/>
<image name="LaunchBackground" width="1" height="1"/>
</resources> </resources>
</document> </document>

View File

@@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
@@ -24,6 +26,29 @@
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneConfigurationName</key>
<string>flutter</string>
<key>UISceneDelegateClassName</key>
<string>FlutterSceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>
@@ -41,9 +66,30 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>CADisableMinimumFrameDurationOnPhone</key> <key>YandexMapKitApiKey</key>
<true/> <string>$(YANDEX_MAPKIT_API_KEY)</string>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>NSLocationWhenInUseUsageDescription</key>
<true/> <string>Данные о местоположении необходимы для поиска ближайших самокатов и отображения их на карте.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Данные о местоположении необходимы для отслеживания поездки на самокате в фоновом режиме.</string>
<key>NSCameraUsageDescription</key>
<string>Приложению нужен доступ к камере для сканирования QR-кодов самокатов</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Приложению нужен доступ к галерее для выбора фото профиля и подтверждения поездки</string>
<key>UIStatusBarHidden</key>
<false/>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>com.behappy.app</string>
<key>CFBundleURLSchemes</key>
<array>
<string>com.behappy.app</string>
</array>
</dict>
</array>
</dict> </dict>
</plist> </plist>

BIN
lib.zip

Binary file not shown.

View File

@@ -21,6 +21,7 @@ import 'package:flutter_client_sse/constants/sse_request_type_enum.dart';
import 'package:flutter_client_sse/flutter_client_sse.dart'; import 'package:flutter_client_sse/flutter_client_sse.dart';
import '../../domain/entities/client_subscription.dart'; import '../../domain/entities/client_subscription.dart';
import '../../domain/entities/fine.dart';
import '../../domain/entities/point.dart'; import '../../domain/entities/point.dart';
import '../../domain/entities/user_profile.dart'; import '../../domain/entities/user_profile.dart';
import '../../domain/entities/payment_card.dart'; import '../../domain/entities/payment_card.dart';
@@ -35,8 +36,11 @@ import '../models/subscriptions_response.dart';
import '../models/user_check_response_dto.dart'; import '../models/user_check_response_dto.dart';
class ApiService { class ApiService {
static const String baseUrl = "https://sharing-api.sparkit.by/api/v1"; static const String baseUrl = "https://api.behappybel.by/api/v1";
static const String fileBaseUrl = "https://sharing-api.sparkit.by"; static const String fileBaseUrl = "https://api.behappybel.by/";
/*static const String baseUrl = "https://sharing-api.sparkit.by/api/v1";
static const String fileBaseUrl = "https://sharing-api.sparkit.by";*/
final SecurityService _securityService; final SecurityService _securityService;
final Dio _dio; final Dio _dio;
@@ -171,6 +175,53 @@ class ApiService {
} }
} }
Future<void> deleteProfile() async {
try {
final response = await _dio.delete(
"$baseUrl/client/me",
options: await _getAuthOptions(),
);
if (response.statusCode == 200) {
final data = response.data;
final profileData = data["profile"];
if (profileData == null) return null;
String? parsedDate;
if (profileData["dob"] != null) {
try {
parsedDate = DateFormat(
'dd.MM.yyyy',
).format(DateTime.parse(profileData["dob"]));
} catch (_) {}
}
final int? avatarId = profileData["avatarId"];
String? avatarUrl;
if (avatarId != null && profileData["avatar"] != null) {
final String? avatarPath = profileData["avatar"]["path"];
if (avatarPath != null && avatarPath.isNotEmpty) {
avatarUrl = Uri.parse(fileBaseUrl).resolve(avatarPath).toString();
}
}
dynamic balanceRaw = profileData["balance"];
double? balance;
if (balanceRaw is num) {
balance = balanceRaw.toDouble();
} else if (balanceRaw is String) {
balance = double.tryParse(balanceRaw);
}
}
return null;
} catch (e) {
return null;
}
}
Future<List<PaymentCard>> getPaymentCards() async { Future<List<PaymentCard>> getPaymentCards() async {
final response = await _dio.get( final response = await _dio.get(
"$baseUrl/client/me", "$baseUrl/client/me",
@@ -447,6 +498,35 @@ class ApiService {
} }
} }
Future<ZonesResponse?> getAllZones({
int page = 1,
int pageSize = 500,
}) async {
const path = "$baseUrl/zone/available2";
final queryParams = {
'readAll': 'true',
'page': page,
'pageSize': pageSize,
};
try {
final response = await _dio.get(
path,
queryParameters: queryParams,
options: await _getAuthOptions(),
);
if (response.statusCode == 200) {
return ZonesResponse.fromJson(response.data);
}
return null;
} catch (e) {
print("ERROR: getZones failed: $e");
return null;
}
}
Future<TariffsResponse?> getAvailableTariffs({required int scooterId}) async { Future<TariffsResponse?> getAvailableTariffs({required int scooterId}) async {
final url = "$baseUrl/scooterplan/$scooterId/available"; final url = "$baseUrl/scooterplan/$scooterId/available";
@@ -934,6 +1014,64 @@ class ApiService {
} }
} }
/// GET /scooterorder/fines/client
Future<List<Fine>> getClientFines() async {
try {
final response = await _dio.get(
"$baseUrl/scooterorder/fines/client",
options: await _getAuthOptions(),
);
if (response.statusCode == 200 && response.data is Map) {
final List<dynamic> dataList = response.data['data'] ?? [];
return dataList.map((json) => Fine.fromJson(json)).toList();
}
return [];
} on DioException catch (e) {
_handleDioError(e);
return [];
}
}
/// GET /scooterorder/{id}/fine
Future<Fine?> getFineDetails(int orderId) async {
try {
final response = await _dio.get(
"$baseUrl/scooterorder/fines/client/$orderId",
options: await _getAuthOptions(),
);
if (response.statusCode == 200 && response.data != null) {
return Fine.fromJson(response.data);
}
return null;
} on DioException catch (e) {
_handleDioError(e);
return null;
}
}
/// PUT /scooterorder/fines/client/{id}
/// {id} — это id штрафа (Fine.id), а не id заказа (Fine.orderId)
Future<void> payFine({
required int orderId,
int? cardId,
required bool isBalance,
}) async {
try {
await _dio.put(
"$baseUrl/scooterorder/fines/client/$orderId",
data: {
"cardId": cardId ?? 0,
"isBalance": isBalance,
},
options: await _getAuthOptions(),
);
} on DioException catch (e) {
_handleDioError(e);
}
}
Future<Map<String, dynamic>> getNews() async { Future<Map<String, dynamic>> getNews() async {
try { try {
final response = await _dio.get( final response = await _dio.get(
@@ -1148,5 +1286,6 @@ class ApiService {
} }
} }
// ✅ Добавь исключение (можно в отдельный файл)
class PromoCodeNotFoundException implements Exception {} class PromoCodeNotFoundException implements Exception {}

View File

@@ -27,6 +27,11 @@ class UserProfileRepositoryImpl implements UserProfileRepository {
return await _apiService.getProfile() ?? _cachedProfile; return await _apiService.getProfile() ?? _cachedProfile;
} }
@override
Future<void> deleteProfile() async {
return await _apiService.deleteProfile();
}
@override @override
Future<UserProfile?> updateProfile(UserProfile profile) async { Future<UserProfile?> updateProfile(UserProfile profile) async {
//await Future.delayed(const Duration(milliseconds: 300)); //await Future.delayed(const Duration(milliseconds: 300));

View File

@@ -1,21 +1,22 @@
import 'dart:io'; import 'dart:io';
import 'package:be_happy/data/exceptions/auth_block_exception.dart';
import 'package:be_happy/data/exceptions/route_history_not_found_exception.dart';
import 'package:be_happy/data/exceptions/scooter_not_found_exception.dart';
import 'package:be_happy/data/exceptions/unauthorized_exception.dart';
import 'package:be_happy/data/exceptions/wrong_zone_exception.dart';
import 'package:be_happy/domain/entities/point.dart';
import 'package:be_happy/domain/repositories/scooter_repository.dart';
import '../../core/failures.dart'; import '../../core/failures.dart';
import '../../core/result.dart'; import '../../core/result.dart';
import '../../domain/entities/active_scooter_order.dart'; import '../../domain/entities/active_scooter_order.dart';
import '../../domain/entities/client_subscription.dart'; import '../../domain/entities/client_subscription.dart';
import '../../domain/entities/fine.dart';
import '../../domain/entities/point.dart';
import '../../domain/entities/scooter.dart'; import '../../domain/entities/scooter.dart';
import '../../domain/entities/tariff.dart'; import '../../domain/entities/tariff.dart';
import '../../domain/entities/subscription.dart'; import '../../domain/entities/subscription.dart';
import '../../domain/entities/scooter_order.dart'; import '../../domain/entities/scooter_order.dart';
import '../../domain/repositories/scooter_repository.dart';
import '../exceptions/auth_block_exception.dart';
import '../exceptions/auth_exception.dart'; import '../exceptions/auth_exception.dart';
import '../exceptions/route_history_not_found_exception.dart';
import '../exceptions/scooter_not_found_exception.dart';
import '../exceptions/unauthorized_exception.dart';
import '../exceptions/wrong_zone_exception.dart';
import '../network/api_service.dart'; import '../network/api_service.dart';
class ScooterRepositoryImpl extends ScooterRepository { class ScooterRepositoryImpl extends ScooterRepository {
@@ -425,4 +426,70 @@ class ScooterRepositoryImpl extends ScooterRepository {
} }
return result; return result;
} }
@override
Future<Result<Fine>> getFineDetails(int orderId) async {
late final Result<Fine> result;
try {
final fine = await _apiService.getFineDetails(orderId);
if (fine != null) {
result = Success(fine);
} else {
result = Failure(UnknownFailure("Не удалось получить данные о штрафе"));
}
} on AuthException catch (e) {
result = Failure(AuthFailure(e.attemptsLeft));
} on UnauthorizedException catch (e) {
result = Failure(AuthFailure(0, message: e.toString()));
} on AuthBlockException catch (e) {
result = Failure(AuthBlockFailure(e.toString()));
} catch (e) {
result = Failure(UnknownFailure("Неизвестная ошибка"));
}
return result;
}
@override
Future<Result<List<Fine>>> getClientFines() async {
late final Result<List<Fine>> result;
try {
final fines = await _apiService.getClientFines();
result = Success(fines);
} on AuthException catch (e) {
result = Failure(AuthFailure(e.attemptsLeft));
} on UnauthorizedException catch (e) {
result = Failure(AuthFailure(0, message: e.toString()));
} on AuthBlockException catch (e) {
result = Failure(AuthBlockFailure(e.toString()));
} catch (e) {
result = Failure(UnknownFailure("Неизвестная ошибка"));
}
return result;
}
@override
Future<Result<void>> payFine({
required int orderId,
int? cardId,
required bool isBalance,
}) async {
late final Result<void> result;
try {
await _apiService.payFine(
orderId: orderId,
cardId: cardId,
isBalance: isBalance,
);
result = Success(null);
} on AuthException catch (e) {
result = Failure(AuthFailure(e.attemptsLeft));
} on UnauthorizedException catch (e) {
result = Failure(AuthFailure(0, message: e.toString()));
} on AuthBlockException catch (e) {
result = Failure(AuthBlockFailure(e.toString()));
} catch (e) {
result = Failure(UnknownFailure("Неизвестная ошибка"));
}
return result;
}
} }

View File

@@ -10,60 +10,60 @@ class ZoneRepositoryImpl extends ZoneRepository {
ZoneRepositoryImpl(this._apiService); ZoneRepositoryImpl(this._apiService);
@override @override
Future<List<Zone>> getZones(List<double> area, Future<List<Zone>> getZones(List<double> area, int page, int pageSize) async {
int page,
int pageSize,) async {
final List<Point> list = []; final List<Point> list = [];
final List<Point> list2 = []; final List<Point> list2 = [];
/*list.add(Point(55.182372,30.203347));
list.add(Point(55.173746,30.200257));
list.add(Point(55.172153,30.212531));
list.add(Point(55.179946,30.215964));
list2.add(Point(55.178304,30.227380));
list2.add(Point(55.178059,30.229654));
list2.add(Point(55.191339,30.234718));
list2.add(Point(55.194352,30.234890));
list2.add(Point(55.194377,30.231972));
list2.add(Point(55.192123,30.232744));
final zone = Zone(id: 123,
title: "Zone 01",
description: "description",
type: "Finish",
isActive: true,
shapeType: "polygon",
points: list,
speedLimit: "speedLimit");
final zone2 = Zone(id: 124,
title: "Zone 02",
description: "description",
type: "NotDrive",
isActive: true,
shapeType: "polygon",
points: list2,
speedLimit: "speedLimit");
*/
final responce = await _apiService.getZones( final responce = await _apiService.getZones(
area: area, area: area,
page: page, page: page,
pageSize: pageSize, pageSize: pageSize,
); );
final List<Zone>? zones = responce?.zones; if (responce == null) {
// zones?.add(zone); throw Exception(
// zones?.add(zone2); 'Failed to load zones for area: empty response from server',
);
print("Scooters: ${zones?.first.title}");
if (responce != null) {
return zones ?? List.empty();
} }
return List.empty(); final zones = responce.zones;
print("Zones: ${zones.length}");
return zones;
}
@override
Future<List<Zone>> getAllZones(int page, int pageSize) async {
final List<Point> list = [];
final List<Point> list2 = [];
final responce = await _apiService.getAllZones(
page: page,
pageSize: pageSize,
);
// apiService.getAllZones ловит свои ошибки (сеть/401/5xx) и в этом
// случае возвращает null. Раньше это тихо превращалось в "зон нет" —
// из-за чего сбой запроса выглядел как легитимный пустой ответ и
// (в связке с кешем на уровне MapBloc) навсегда "прятал" зоны на
// время сессии. Бросаем исключение, чтобы вызывающий код (usecase/bloc)
// мог отличить реальный сбой от честного "зон действительно нет"
// и, при необходимости, повторить запрос.
if (responce == null) {
throw Exception('Failed to load zones: empty response from server');
}
final zones = responce.zones;
print(zones.map((z) => '${z.type}:${z.id}'));
for (final z in zones) {
print("Zone ${z.type}:${z.id} geometry.length=${z.geometry.length}");
}
print("Zones: ${zones.length}");
return zones;
} }
} }

View File

@@ -10,6 +10,6 @@ class AppSettingsService {
} }
bool getMapSettingsFlag(String key) { bool getMapSettingsFlag(String key) {
return sharedPreferences.getBool(key) ?? false; return sharedPreferences.getBool(key) ?? true;
} }
} }

View File

@@ -17,6 +17,8 @@ import 'package:be_happy/domain/repositories/scooter_repository.dart';
import 'package:be_happy/domain/repositories/zone_repository.dart'; import 'package:be_happy/domain/repositories/zone_repository.dart';
import 'package:be_happy/domain/service/security_service.dart'; import 'package:be_happy/domain/service/security_service.dart';
import 'package:be_happy/domain/usecase/add_payment_card_usecase.dart'; // ← новый import 'package:be_happy/domain/usecase/add_payment_card_usecase.dart'; // ← новый
import 'package:be_happy/domain/usecase/delete_profile_usecase.dart';
import 'package:be_happy/domain/usecase/get_all_zones_usecase.dart';
import 'package:be_happy/domain/usecase/get_certificates_usecase.dart'; import 'package:be_happy/domain/usecase/get_certificates_usecase.dart';
import 'package:be_happy/domain/usecase/get_scooter_order_route_history_usecase.dart'; import 'package:be_happy/domain/usecase/get_scooter_order_route_history_usecase.dart';
import 'package:be_happy/domain/usecase/is_pin_set_usecase.dart'; import 'package:be_happy/domain/usecase/is_pin_set_usecase.dart';
@@ -54,6 +56,7 @@ import 'package:be_happy/domain/usecase/finish_ride_usecase.dart';
import 'package:be_happy/domain/usecase/pause_ride_usecase.dart'; import 'package:be_happy/domain/usecase/pause_ride_usecase.dart';
import 'package:be_happy/domain/usecase/resume_ride_usecase.dart'; import 'package:be_happy/domain/usecase/resume_ride_usecase.dart';
import 'package:be_happy/domain/usecase/verify_pin_usecase.dart'; import 'package:be_happy/domain/usecase/verify_pin_usecase.dart';
import 'package:be_happy/presentation/event/profile_event.dart';
import 'package:be_happy/presentation/viewmodel/active_ride_bloc.dart'; import 'package:be_happy/presentation/viewmodel/active_ride_bloc.dart';
import 'package:be_happy/presentation/viewmodel/add_card_bloc.dart'; // ← новый import 'package:be_happy/presentation/viewmodel/add_card_bloc.dart'; // ← новый
import 'package:be_happy/presentation/viewmodel/current_rides_bloc.dart'; import 'package:be_happy/presentation/viewmodel/current_rides_bloc.dart';
@@ -94,14 +97,18 @@ import '../domain/service/device_info_service.dart';
import '../domain/usecase/activate_subscription_usecase.dart'; import '../domain/usecase/activate_subscription_usecase.dart';
import '../domain/usecase/apply_promo_code_usecase.dart'; import '../domain/usecase/apply_promo_code_usecase.dart';
import '../domain/usecase/get_client_subscriptions_usecase.dart'; import '../domain/usecase/get_client_subscriptions_usecase.dart';
import '../domain/usecase/get_fine_details_usecase.dart';
import '../domain/usecase/get_fines_usecase.dart';
import '../domain/usecase/get_news_by_id_usecase.dart'; import '../domain/usecase/get_news_by_id_usecase.dart';
import '../domain/usecase/get_notifications_usecase.dart'; import '../domain/usecase/get_notifications_usecase.dart';
import '../domain/usecase/get_scooter_by_title_usecase.dart'; import '../domain/usecase/get_scooter_by_title_usecase.dart';
import '../domain/usecase/get_scooter_order_history_usecase.dart'; import '../domain/usecase/get_scooter_order_history_usecase.dart';
import '../domain/usecase/pay_fine_usecase.dart';
import '../domain/usecase/remove_payment_card_usecase.dart'; import '../domain/usecase/remove_payment_card_usecase.dart';
import '../domain/usecase/set_main_payment_card_usecase.dart'; import '../domain/usecase/set_main_payment_card_usecase.dart';
import '../presentation/viewmodel/auth_bloc.dart'; import '../presentation/viewmodel/auth_bloc.dart';
import '../presentation/viewmodel/edit_profile_bloc.dart'; import '../presentation/viewmodel/edit_profile_bloc.dart';
import '../presentation/viewmodel/fine_list_bloc.dart';
import '../presentation/viewmodel/map_bloc.dart'; import '../presentation/viewmodel/map_bloc.dart';
import '../presentation/viewmodel/news_bloc.dart'; import '../presentation/viewmodel/news_bloc.dart';
import '../presentation/viewmodel/notifications_bloc.dart'; import '../presentation/viewmodel/notifications_bloc.dart';
@@ -116,7 +123,13 @@ final getIt = GetIt.instance;
Future<void> setupDependencies() async { Future<void> setupDependencies() async {
final sharedPreferences = await SharedPreferences.getInstance(); final sharedPreferences = await SharedPreferences.getInstance();
final dio = Dio(); final dio = Dio();
dio.interceptors.add(LogInterceptor(/*requestHeader: false, responseHeader:false, */responseBody: true, requestBody: true)); dio.interceptors.add(
LogInterceptor(
/*requestHeader: false, responseHeader:false, */
responseBody: true,
requestBody: true,
),
);
dio.interceptors.add(AuthInterceptor()); dio.interceptors.add(AuthInterceptor());
// HTTP // HTTP
getIt.registerSingleton<http.Client>(http.Client()); getIt.registerSingleton<http.Client>(http.Client());
@@ -195,6 +208,8 @@ Future<void> setupDependencies() async {
getIt.registerSingleton<GetProfileUseCase>(GetProfileUseCase(getIt())); getIt.registerSingleton<GetProfileUseCase>(GetProfileUseCase(getIt()));
getIt.registerSingleton<DeleteProfileUsecase>(DeleteProfileUsecase(getIt(), getIt(), getIt()));
getIt.registerSingleton<UpdateProfileUseCase>(UpdateProfileUseCase(getIt())); getIt.registerSingleton<UpdateProfileUseCase>(UpdateProfileUseCase(getIt()));
getIt.registerSingleton<UploadProfilePhotoUsecase>( getIt.registerSingleton<UploadProfilePhotoUsecase>(
@@ -225,6 +240,9 @@ Future<void> setupDependencies() async {
getIt.registerSingleton<GetAvailableZonesUsecase>( getIt.registerSingleton<GetAvailableZonesUsecase>(
GetAvailableZonesUsecase(getIt()), GetAvailableZonesUsecase(getIt()),
); );
getIt.registerSingleton<GetAllZonesUsecase>(
GetAllZonesUsecase(getIt()),
);
getIt.registerSingleton<GetMapSettingsUsecase>( getIt.registerSingleton<GetMapSettingsUsecase>(
GetMapSettingsUsecase(getIt()), GetMapSettingsUsecase(getIt()),
); );
@@ -299,15 +317,18 @@ Future<void> setupDependencies() async {
() => NotificationsBloc(getIt<GetNotificationsUsecase>()), () => NotificationsBloc(getIt<GetNotificationsUsecase>()),
); );
// Blocs // Blocs
getIt.registerLazySingleton<SplashBloc>(() => SplashBloc(getIt())); getIt.registerLazySingleton<SplashBloc>(() => SplashBloc(getIt()));
getIt.registerFactory<PhoneAuthBloc>(() => PhoneAuthBloc(getIt())); getIt.registerFactory<PhoneAuthBloc>(() => PhoneAuthBloc(getIt()));
getIt.registerFactory<VerifyCodeBloc>(() => VerifyCodeBloc(getIt(), getIt(), getIt())); getIt.registerFactory<VerifyCodeBloc>(
() => VerifyCodeBloc(getIt(), getIt(), getIt()),
);
getIt.registerLazySingleton<ProfileBloc>(() => ProfileBloc(getIt(), getIt(), getIt())); getIt.registerLazySingleton<ProfileBloc>(
() => ProfileBloc(getIt(), getIt(), getIt(), getIt(), getIt(), getIt()),
);
getIt.registerFactory<EditProfileBloc>( getIt.registerFactory<EditProfileBloc>(
() => EditProfileBloc(getIt(), getIt()), () => EditProfileBloc(getIt(), getIt()),
@@ -335,7 +356,6 @@ Future<void> setupDependencies() async {
getIt.registerFactory<AddCardBloc>(() => AddCardBloc(getIt())); getIt.registerFactory<AddCardBloc>(() => AddCardBloc(getIt()));
getIt.registerFactory<PaymentMethodSheetBloc>( getIt.registerFactory<PaymentMethodSheetBloc>(
() => PaymentMethodSheetBloc(getIt(), getIt(), getIt(), getIt()), () => PaymentMethodSheetBloc(getIt(), getIt(), getIt(), getIt()),
); );
@@ -352,7 +372,6 @@ Future<void> setupDependencies() async {
getIt.registerFactory<NewsBloc>(() => NewsBloc(getIt<NewsRepository>())); getIt.registerFactory<NewsBloc>(() => NewsBloc(getIt<NewsRepository>()));
getIt.registerFactory<SendPhotoBloc>(() => SendPhotoBloc(getIt(), getIt())); getIt.registerFactory<SendPhotoBloc>(() => SendPhotoBloc(getIt(), getIt()));
getIt.registerFactory<SubscriptionListBloc>( getIt.registerFactory<SubscriptionListBloc>(
@@ -384,10 +403,15 @@ Future<void> setupDependencies() async {
() => OrderHistoryBloc(getIt<GetScooterOrderHistoryUsecase>()), () => OrderHistoryBloc(getIt<GetScooterOrderHistoryUsecase>()),
); );
getIt.registerFactory<ScooterCodeBloc>( getIt.registerFactory<FineListBloc>(() => FineListBloc(getIt()));
() => ScooterCodeBloc(getScooterByTitleUsecase: getIt<GetScooterByTitleUsecase>()),
);
getIt.registerFactory<ScooterCodeBloc>(
() => ScooterCodeBloc(
getScooterByTitleUsecase: getIt<GetScooterByTitleUsecase>(),
getAddressUsecase: getIt<GetAddressByPointUsecase>(),
getPedestrianRoutesUsecase: getIt<GetPedestrianRoutesUsecase>()
),
);
// Repository // Repository
getIt.registerSingleton<PromoCodeRepository>( getIt.registerSingleton<PromoCodeRepository>(
@@ -399,6 +423,12 @@ Future<void> setupDependencies() async {
ApplyPromoCodeUsecase(getIt<PromoCodeRepository>()), ApplyPromoCodeUsecase(getIt<PromoCodeRepository>()),
); );
getIt.registerFactory<GetFinesUsecase>(() => GetFinesUsecase(getIt()));
getIt.registerFactory<GetFineDetailsUsecase>(() => GetFineDetailsUsecase(getIt()));
getIt.registerFactory<PayFineUsecase>(() => PayFineUsecase(getIt()));
// Bloc (factory, т.к. экран создаёт новый экземпляр) // Bloc (factory, т.к. экран создаёт новый экземпляр)
getIt.registerFactory<PromoCodeBloc>( getIt.registerFactory<PromoCodeBloc>(
() => PromoCodeBloc(getIt<ApplyPromoCodeUsecase>()), () => PromoCodeBloc(getIt<ApplyPromoCodeUsecase>()),

View File

@@ -0,0 +1,62 @@
import 'package:equatable/equatable.dart';
class Fine extends Equatable {
final int id;
final int orderId; // ← добавлено
final String scooterNumber; // можно оставить для совместимости, но не использовать в UI
final DateTime createdAtDateTime; // ← новое поле
final String description;
final double amount;
final String amountPrint;
final List<String> photoUrls;
final bool isPaid;
const Fine({
required this.id,
required this.orderId,
required this.scooterNumber,
required this.createdAtDateTime,
required this.description,
required this.amount,
required this.amountPrint,
required this.photoUrls,
required this.isPaid,
});
factory Fine.fromJson(Map<String, dynamic> json, {String? scooterNumber}) {
final List<dynamic> filesJson = json['files'] ?? [];
final List<String> photos = filesJson
.map((file) => file['path'] as String? ?? file['filename'] as String? ?? '')
.where((path) => path.isNotEmpty)
.toList();
// Парсим createdAt как DateTime
final createdAtDateTime = DateTime.tryParse(json['createdAt'].toString()) ??
DateTime.now(); // fallback
return Fine(
id: json['id'] as int? ?? 0,
orderId: json['orderId'] as int? ?? 0,
scooterNumber: scooterNumber ?? '',
createdAtDateTime: createdAtDateTime,
description: json['description'] as String? ?? '',
amount: (json['value'] as num?)?.toDouble() ?? 0.0,
amountPrint: json['valuePrint'] as String? ?? '0,00 BYN',
photoUrls: photos,
isPaid: json['isPaid'] as bool? ?? false,
);
}
@override
List<Object?> get props => [
id,
orderId,
scooterNumber,
createdAtDateTime,
description,
amount,
amountPrint,
photoUrls,
isPaid,
];
}

View File

@@ -6,10 +6,10 @@ class MapSettings {
final bool restricted_driving_zones; final bool restricted_driving_zones;
MapSettings({ MapSettings({
required this.all_placemarks, this.all_placemarks = true,
required this.all_zones, this.all_zones = true,
required this.parking_zones, this.parking_zones = true,
required this.restricted_parking_zones, this.restricted_parking_zones = true,
required this.restricted_driving_zones, this.restricted_driving_zones = true,
}); });
} }

View File

@@ -27,11 +27,12 @@ class ScooterOrder {
final DateTime? expiresAt; final DateTime? expiresAt;
final DateTime? cancelAt; final DateTime? cancelAt;
final String? cancelDescription; final String? cancelDescription;
final double mileage; //эту final double mileage;
final double avgSpeed; //эту и снизу еще 4 есть final double avgSpeed;
final String payTotalPricePrint; final String payTotalPricePrint;
final String unpayTotalPricePrint; final String unpayTotalPricePrint;
final String totalOrderPricePrint; final String totalOrderPricePrint;
final bool hasFine;
ScooterOrder({ ScooterOrder({
required this.id, required this.id,
@@ -65,6 +66,7 @@ class ScooterOrder {
required this.payTotalPricePrint, // оплачено required this.payTotalPricePrint, // оплачено
required this.unpayTotalPricePrint, //неоплачено required this.unpayTotalPricePrint, //неоплачено
required this.totalOrderPricePrint, //общая required this.totalOrderPricePrint, //общая
required this.hasFine,
}); });
factory ScooterOrder.fromJson(Map<String, dynamic> json) { factory ScooterOrder.fromJson(Map<String, dynamic> json) {
@@ -114,6 +116,7 @@ class ScooterOrder {
payTotalPricePrint: paymentInfo?['payTotalPricePrint'] ?? '', payTotalPricePrint: paymentInfo?['payTotalPricePrint'] ?? '',
unpayTotalPricePrint: paymentInfo?['unpayTotalPricePrint'] ?? '', unpayTotalPricePrint: paymentInfo?['unpayTotalPricePrint'] ?? '',
totalOrderPricePrint: paymentInfo?['totalOrderPricePrint'] ?? '', totalOrderPricePrint: paymentInfo?['totalOrderPricePrint'] ?? '',
hasFine: paymentInfo?['hasFine'] ?? false,
); );
} }

View File

@@ -10,6 +10,7 @@ class Tariff {
final double startPrice; // Старт цена final double startPrice; // Старт цена
final double cashback; // Процент кэшбэка final double cashback; // Процент кэшбэка
final double insurance; // Страховка final double insurance; // Страховка
final int subscriptionId;
Tariff({ Tariff({
required this.id, required this.id,
@@ -23,6 +24,7 @@ class Tariff {
required this.startPrice, required this.startPrice,
required this.cashback, required this.cashback,
required this.insurance, required this.insurance,
required this.subscriptionId,
}); });
factory Tariff.fromJson(Map<String, dynamic> json) { factory Tariff.fromJson(Map<String, dynamic> json) {
@@ -41,6 +43,7 @@ class Tariff {
startPrice: (planPrice['start'] as num?)?.toDouble() ?? 0.0, startPrice: (planPrice['start'] as num?)?.toDouble() ?? 0.0,
cashback: (planPrice['cashback'] as num?)?.toDouble() ?? 0.0, cashback: (planPrice['cashback'] as num?)?.toDouble() ?? 0.0,
insurance: (planPrice['insurance'] as num?)?.toDouble() ?? 0.0, insurance: (planPrice['insurance'] as num?)?.toDouble() ?? 0.0,
subscriptionId: json.containsKey('subscriptionId') ? json['subscriptionId'] : 0,
); );
} }

View File

@@ -1,4 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:be_happy/domain/entities/point.dart'; import 'package:be_happy/domain/entities/point.dart';
class Zone { class Zone {
@@ -8,9 +10,6 @@ class Zone {
final String type; final String type;
final bool isActive; final bool isActive;
final String shapeType; final String shapeType;
// Трехмерная структура для поддержки MultiPolygon и дыр (holes):
// geometry[индекс_полигона][индекс_кольца][индекс_точки]
// индекс_кольца == 0 — внешняя граница, > 0 — внутренние вырезы (дыры)
final List<List<List<Point>>> geometry; final List<List<List<Point>>> geometry;
final String speedLimit; final String speedLimit;
@@ -25,7 +24,6 @@ class Zone {
required this.speedLimit, required this.speedLimit,
}); });
// Геттер для обратной совместимости (возвращает внешнее кольцо первого полигона)
List<Point> get points { List<Point> get points {
if (geometry.isNotEmpty && geometry[0].isNotEmpty) { if (geometry.isNotEmpty && geometry[0].isNotEmpty) {
return geometry[0][0]; return geometry[0][0];
@@ -45,51 +43,54 @@ class Zone {
if (decoded is List && decoded.isNotEmpty) { if (decoded is List && decoded.isNotEmpty) {
if (shapeType == 'Polygon') { if (shapeType == 'Polygon') {
// Структура: [[[lon, lat], [lon, lat], ...], [hole1], ...] final polygonRings = _parseRings(decoded);
List<List<Point>> polygonRings = [];
for (var ring in decoded) {
if (ring is List) {
List<Point> ringPoints = [];
for (var coord in ring) {
if (coord is List && coord.length >= 2) {
// В GeoJSON сначала идет Longitude, затем Latitude
ringPoints.add(Point(
(coord[1] as num).toDouble(),
(coord[0] as num).toDouble(),
));
}
}
if (ringPoints.isNotEmpty) polygonRings.add(ringPoints);
}
}
if (polygonRings.isNotEmpty) parsedGeometry.add(polygonRings); if (polygonRings.isNotEmpty) parsedGeometry.add(polygonRings);
} else if (shapeType == 'MultiPolygon') { } else if (shapeType == 'MultiPolygon') {
// Структура: [[[[lon, lat], ...]], [[[lon, lat], ...]]]
for (var poly in decoded) { for (var poly in decoded) {
if (poly is List) { if (poly is List) {
List<List<Point>> polygonRings = []; final polygonRings = _parseRings(poly);
for (var ring in poly) {
if (ring is List) {
List<Point> ringPoints = [];
for (var coord in ring) {
if (coord is List && coord.length >= 2) {
ringPoints.add(Point(
(coord[1] as num).toDouble(),
(coord[0] as num).toDouble(),
));
}
}
if (ringPoints.isNotEmpty) polygonRings.add(ringPoints);
}
}
if (polygonRings.isNotEmpty) parsedGeometry.add(polygonRings); if (polygonRings.isNotEmpty) parsedGeometry.add(polygonRings);
} }
} }
} else { } else {
// Fallback для LineString или плоских списков final singleRing = _parseCoordinateList(decoded);
if (singleRing.isNotEmpty) parsedGeometry.add([singleRing]);
}
}
} catch (e, stackTrace) {
// Replace with your project logger (e.g., debugPrint or Logger)
assert(() {
print("PARSE ERROR for Zone ID ${json['id']}: $e\n$stackTrace");
return true;
}());
}
return Zone(
id: json['id'] as int? ?? 0,
title: json['title'] as String? ?? 'Unknown',
description: json['description'] as String? ?? '',
type: json['type'] as String? ?? '',
isActive: json['isActive'] as bool? ?? false,
speedLimit: json['speedLimit'] as String? ?? '',
shapeType: shapeType,
geometry: parsedGeometry,
);
}
static List<List<Point>> _parseRings(List rawRings) {
List<List<Point>> polygonRings = [];
for (var ring in rawRings) {
if (ring is List) {
final ringPoints = _parseCoordinateList(ring);
if (ringPoints.isNotEmpty) polygonRings.add(ringPoints);
}
}
return polygonRings;
}
static List<Point> _parseCoordinateList(List rawCoords) {
List<Point> ringPoints = []; List<Point> ringPoints = [];
for (var coord in decoded) { for (var coord in rawCoords) {
if (coord is List && coord.length >= 2) { if (coord is List && coord.length >= 2) {
ringPoints.add(Point( ringPoints.add(Point(
(coord[1] as num).toDouble(), (coord[1] as num).toDouble(),
@@ -97,23 +98,7 @@ class Zone {
)); ));
} }
} }
if (ringPoints.isNotEmpty) parsedGeometry.add([ringPoints]); return ringPoints;
}
}
} catch (e) {
print("PARSE ERROR for Zone ID ${json['id']}: $e");
}
return Zone(
id: json['id'] ?? 0,
title: json['title'] ?? 'Unknown',
description: json['description'] ?? '',
type: json['type'] ?? '',
isActive: json['isActive'] ?? false,
speedLimit: json['speedLimit'] ?? '',
shapeType: shapeType,
geometry: parsedGeometry,
);
} }
@override @override

View File

@@ -5,6 +5,7 @@ import '../entities/user_profile.dart';
abstract class UserProfileRepository { abstract class UserProfileRepository {
Future<UserProfile> getProfile(); Future<UserProfile> getProfile();
Future<void> deleteProfile();
Future<UserProfile?> updateProfile(UserProfile profile); Future<UserProfile?> updateProfile(UserProfile profile);
Future<int?> uploadProfilePhoto(File imageFile); Future<int?> uploadProfilePhoto(File imageFile);
Future<UserCheckFlags?> checkUser(); Future<UserCheckFlags?> checkUser();

View File

@@ -5,6 +5,7 @@ import 'package:be_happy/domain/entities/active_scooter_order.dart';
import '../../core/result.dart'; import '../../core/result.dart';
import '../entities/client_subscription.dart'; import '../entities/client_subscription.dart';
import '../entities/fine.dart';
import '../entities/point.dart'; import '../entities/point.dart';
import '../entities/scooter.dart'; import '../entities/scooter.dart';
import '../entities/subscription.dart'; import '../entities/subscription.dart';
@@ -53,4 +54,14 @@ abstract class ScooterRepository {
Future<Result<List<Point>>> getScooterOrderRouteHistory(int id); Future<Result<List<Point>>> getScooterOrderRouteHistory(int id);
Future<Result<Fine>> getFineDetails(int orderId);
Future<Result<void>> payFine({
required int orderId,
int? cardId,
required bool isBalance,
});
Future<Result<List<Fine>>> getClientFines();
} }

View File

@@ -2,5 +2,6 @@ import '../entities/zone.dart';
abstract class ZoneRepository { abstract class ZoneRepository {
Future<List<Zone>> getZones(List<double> area, int page, int pageSize); Future<List<Zone>> getZones(List<double> area, int page, int pageSize);
Future<List<Zone>> getAllZones(int page, int pageSize);
} }

View File

@@ -0,0 +1,21 @@
import '../entities/user_profile.dart';
import '../repositories/auth_repository.dart';
import '../repositories/pin_repository.dart';
import '../repositories/profile_repository.dart';
class DeleteProfileUsecase {
final UserProfileRepository repository;
final PinRepository _pinRepository;
final AuthRepository _authRepository;
DeleteProfileUsecase(this.repository, this._pinRepository, this._authRepository);
Future<void> call() {
_pinRepository.removePin();
repository.deleteProfile();
return _authRepository.logout();
}
}

View File

@@ -0,0 +1,30 @@
import '../entities/zone.dart';
import '../repositories/zone_repository.dart';
class GetAllZonesUsecase {
final ZoneRepository repository;
GetAllZonesUsecase(this.repository);
static const int _pageSize = 100;
Future<List<Zone>> call() async {
final List<Zone> allZones = [];
int page = 0;
while (true) {
final zones = await repository.getAllZones(page, _pageSize);
if (zones == null || zones.isEmpty) break;
allZones.addAll(zones);
// если пришло меньше, чем размер страницы — это последняя страница
if (zones.length < _pageSize) break;
page++;
}
return allZones;
}
}

View File

@@ -0,0 +1,14 @@
import 'package:be_happy/core/result.dart';
import '../entities/fine.dart';
import '../repositories/scooter_repository.dart';
class GetFineDetailsUsecase {
final ScooterRepository repository;
GetFineDetailsUsecase(this.repository);
Future<Result<Fine>> call(int orderId) {
return repository.getFineDetails(orderId);
}
}

View File

@@ -0,0 +1,13 @@
import '../../core/result.dart';
import '../entities/fine.dart';
import '../repositories/scooter_repository.dart';
class GetFinesUsecase {
final ScooterRepository repository;
GetFinesUsecase(this.repository);
Future<Result<List<Fine>>> call() {
return repository.getClientFines();
}
}

View File

@@ -0,0 +1,21 @@
import '../../core/result.dart';
import '../entities/fine.dart';
import '../repositories/scooter_repository.dart';
class PayFineUsecase {
final ScooterRepository repository;
PayFineUsecase(this.repository);
Future<Result<void>> call({
required int orderId,
int? cardId,
required bool isBalance,
}) {
return repository.payFine(
orderId: orderId,
cardId: cardId,
isBalance: isBalance,
);
}
}

View File

@@ -1,3 +1,4 @@
import 'package:be_happy/domain/entities/map_settings.dart'; import 'package:be_happy/domain/entities/map_settings.dart';
import '../repositories/app_settings_repository.dart'; import '../repositories/app_settings_repository.dart';

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; // 🔹 1. Добавлен импорт import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:bot_toast/bot_toast.dart'; import 'package:bot_toast/bot_toast.dart';
import 'package:be_happy/presentation/event/edit_profile_event.dart'; import 'package:be_happy/presentation/event/edit_profile_event.dart';
import 'package:be_happy/presentation/event/profile_event.dart'; import 'package:be_happy/presentation/event/profile_event.dart';
@@ -69,6 +70,14 @@ class MyApp extends StatelessWidget {
title: 'BeHappy', title: 'BeHappy',
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
theme: ThemeData.dark(), theme: ThemeData.dark(),
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('ru', 'RU'),
],
builder: BotToastInit(), builder: BotToastInit(),
routerConfig: appRouter.router, routerConfig: appRouter.router,
), ),

View File

@@ -2,13 +2,15 @@ import 'package:flutter/material.dart';
class CustomAppBar extends StatelessWidget { class CustomAppBar extends StatelessWidget {
final String title; final String title;
final showBackButton;
const CustomAppBar({super.key, required this.title}); const CustomAppBar({super.key, required this.title, this.showBackButton = true});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Row( return Row(
children: [ children: [
if (showBackButton)
InkWell( InkWell(
onTap: () => Navigator.pop(context), onTap: () => Navigator.pop(context),
child: Row( child: Row(

View File

@@ -0,0 +1,94 @@
import 'package:flutter/material.dart';
class DeleteAccountDialog extends StatelessWidget {
const DeleteAccountDialog({super.key});
@override
Widget build(BuildContext context) {
return Dialog(
backgroundColor: Colors.transparent,
insetPadding: const EdgeInsets.symmetric(horizontal: 40),
child: Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: const Color(0xFF2E3253).withOpacity(0.95),
borderRadius: BorderRadius.circular(28),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
"Удалить\nучётную запись?",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.w600,
height: 1.2,
),
),
const SizedBox(height: 16),
const Text(
"Это действие необратимо. Все ваши\nданные будут удалены безвозвратно",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white70,
fontSize: 14,
height: 1.4,
),
),
const SizedBox(height: 24),
Container(
width: double.infinity,
height: 52,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(26),
gradient: const LinearGradient(
colors: [Color(0xFFFF8E8E), Color(0xFFFE5F86)],
),
),
child: ElevatedButton(
onPressed: () => Navigator.pop(context, true),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(26),
),
),
child: const Text(
"Удалить",
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
height: 52,
child: ElevatedButton(
onPressed: () => Navigator.pop(context, false),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF0D1024),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(26),
),
),
child: const Text(
"Отмена",
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
class FullScreenImageViewer extends StatefulWidget {
final List<String> photoUrls;
final int initialIndex;
const FullScreenImageViewer({
super.key,
required this.photoUrls,
required this.initialIndex,
});
@override
State<FullScreenImageViewer> createState() => _FullScreenImageViewerState();
}
class _FullScreenImageViewerState extends State<FullScreenImageViewer> {
late PageController _pageController;
@override
void initState() {
super.initState();
_pageController = PageController(initialPage: widget.initialIndex);
}
String _resolveImageUrl(String path) {
if (path.startsWith('http://') || path.startsWith('https://')) return path;
return 'https://sharing-api.sparkit.by/$path';
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
backgroundColor: Colors.transparent,
iconTheme: const IconThemeData(color: Colors.white),
),
body: PageView.builder(
controller: _pageController,
itemCount: widget.photoUrls.length,
itemBuilder: (context, index) {
final photo = widget.photoUrls[index];
final imageUrl = _resolveImageUrl(photo);
return InteractiveViewer(
child: Center(
child: Image.network(
imageUrl,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
return const Icon(Icons.error, color: Colors.white, size: 64);
},
),
),
);
},
),
);
}
}

View File

@@ -101,7 +101,6 @@ class _ScooterBottomSheetState extends State<ScooterBottomSheet> {
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
// PageView с динамическим списком
SizedBox( SizedBox(
height: 220, height: 220,
child: PageView.builder( child: PageView.builder(
@@ -115,8 +114,6 @@ class _ScooterBottomSheetState extends State<ScooterBottomSheet> {
return AnimatedContainer( return AnimatedContainer(
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
// 2. Добавляем левый отступ ТОЛЬКО для первого элемента,
// чтобы он совпадал с заголовком
margin: EdgeInsets.only( margin: EdgeInsets.only(
left: index == 0 ? 20 : 0, left: index == 0 ? 20 : 0,
right: 16, right: 16,
@@ -243,7 +240,7 @@ class _ScooterCard extends StatelessWidget {
showArrows: true, showArrows: true,
height: 32, height: 32,
width: double.infinity, width: double.infinity,
fontSize: 12, fontSize: 11,
onTap: () { onTap: () {
context.go('/home/scooter/${scooter.id}', extra: [address, scooter.distance]); context.go('/home/scooter/${scooter.id}', extra: [address, scooter.distance]);
}, },

Some files were not shown because too many files have changed in this diff Show More