This commit is contained in:
mohamadmahdi jebeli 2025-05-03 11:13:40 +03:30
commit a8a42c839c
161 changed files with 8033 additions and 0 deletions

45
.gitignore vendored Normal file
View File

@ -0,0 +1,45 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

45
.metadata Normal file
View File

@ -0,0 +1,45 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "ea121f8859e4b13e47a8f845e4586164519588bc"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- platform: android
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- platform: ios
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- platform: linux
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- platform: macos
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- platform: web
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- platform: windows
create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

16
README.md Normal file
View File

@ -0,0 +1,16 @@
# lba
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

28
analysis_options.yaml Normal file
View File

@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

14
android/.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
.cxx/
# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks

View File

@ -0,0 +1,44 @@
plugins {
id("com.android.application")
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
}
android {
namespace = "com.example.lba"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.lba"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
}
}
}
flutter {
source = "../.."
}

View File

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,45 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="lba"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>

View File

@ -0,0 +1,5 @@
package com.example.lba
import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity()

View File

@ -0,0 +1,12 @@
<?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">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

View File

@ -0,0 +1,12 @@
<?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">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</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

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</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

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

21
android/build.gradle.kts Normal file
View File

@ -0,0 +1,21 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}

View File

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip

View File

@ -0,0 +1,25 @@
pluginManagement {
val flutterSdkPath = run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val flutterSdkPath = properties.getProperty("flutter.sdk")
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
flutterSdkPath
}
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.0" apply false
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
}
include(":app")

View File

@ -0,0 +1,3 @@
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="25" cy="25" r="25" fill="#261684"/>
</svg>

After

Width:  |  Height:  |  Size: 151 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.00001 11.2C7.53335 11.2 7.06668 11.02 6.71335 10.6667L2.36668 6.32C2.17335 6.12667 2.17335 5.80667 2.36668 5.61334C2.56001 5.42 2.88001 5.42 3.07335 5.61334L7.42001 9.96C7.74001 10.28 8.26001 10.28 8.58001 9.96L12.9267 5.61334C13.12 5.42 13.44 5.42 13.6333 5.61334C13.8267 5.80667 13.8267 6.12667 13.6333 6.32L9.28668 10.6667C8.93335 11.02 8.46668 11.2 8.00001 11.2Z" fill="#2196F3"/>
</svg>

After

Width:  |  Height:  |  Size: 500 B

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 19.92L8.48 13.4C7.71 12.63 7.71 11.37 8.48 10.6L15 4.07996" stroke="#292D32" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 284 B

3
assets/icons/back.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 19.92L8.47997 13.4C7.70997 12.63 7.70997 11.37 8.47997 10.6L15 4.07999" stroke="#292D32" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 277 B

18
assets/icons/clander.svg Normal file
View File

@ -0,0 +1,18 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2592_2449)">
<path d="M12 6V9" stroke="#9D9D9B" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M20 6V9" stroke="#9D9D9B" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M22.2 25.4C23.9673 25.4 25.4 23.9673 25.4 22.2C25.4 20.4327 23.9673 19 22.2 19C20.4327 19 19 20.4327 19 22.2C19 23.9673 20.4327 25.4 22.2 25.4Z" stroke="#9D9D9B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M26 26L25 25" stroke="#9D9D9B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.5 13.09H24.5" stroke="#9D9D9B" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M17.37 26H12C8.5 26 7 24 7 21V12.5C7 9.5 8.5 7.5 12 7.5H20C23.5 7.5 25 9.5 25 12.5V17" stroke="#9D9D9B" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15.9955 17.7H16.0045" stroke="#9D9D9B" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.2943 17.7H12.3033" stroke="#9D9D9B" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.2943 20.7H12.3033" stroke="#9D9D9B" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_2592_2449">
<rect width="32" height="32" rx="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,4 @@
<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.50003 10.0725C10.7924 10.0725 11.84 9.0248 11.84 7.73246C11.84 6.44011 10.7924 5.39246 9.50003 5.39246C8.20769 5.39246 7.16003 6.44011 7.16003 7.73246C7.16003 9.0248 8.20769 10.0725 9.50003 10.0725Z" stroke="#0E3F66" stroke-width="1.5"/>
<path d="M3.21503 6.3675C4.69253 -0.127498 14.315 -0.119998 15.785 6.375C16.6475 10.185 14.2775 13.41 12.2 15.405C10.6925 16.86 8.30753 16.86 6.79253 15.405C4.72253 13.41 2.35253 10.1775 3.21503 6.3675Z" stroke="#0E3F66" stroke-width="1.5"/>
</svg>

After

Width:  |  Height:  |  Size: 595 B

4
assets/icons/next.svg Normal file
View File

@ -0,0 +1,4 @@
<svg width="66" height="50" viewBox="0 0 66 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="33" cy="25" r="25" fill="#261684"/>
<path d="M29.91 32.92L36.43 26.4C37.2 25.63 37.2 24.37 36.43 23.6L29.91 17.08" stroke="#E9F5FE" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 338 B

View File

@ -0,0 +1,3 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.25049 1.5C11.9765 1.5 15.0005 4.524 15.0005 8.25C15.0005 11.976 11.9765 15 8.25049 15C4.52449 15 1.50049 11.976 1.50049 8.25C1.50049 4.524 4.52449 1.5 8.25049 1.5ZM8.25049 13.5C11.1507 13.5 13.5005 11.1503 13.5005 8.25C13.5005 5.349 11.1507 3 8.25049 3C5.34949 3 3.00049 5.349 3.00049 8.25C3.00049 11.1503 5.34949 13.5 8.25049 13.5ZM14.6142 13.5532L16.736 15.6742L15.6747 16.7355L13.5537 14.6138L14.6142 13.5532Z" fill="#808080"/>
</svg>

After

Width:  |  Height:  |  Size: 546 B

View File

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 2H3.74001C4.82001 2 5.67 2.93 5.58 4L4.75 13.96C4.61 15.59 5.89999 16.99 7.53999 16.99H18.19C19.63 16.99 20.89 15.81 21 14.38L21.54 6.88C21.66 5.22 20.4 3.87 18.73 3.87H5.82001" stroke="#2196F3" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16.25 22C16.9404 22 17.5 21.4404 17.5 20.75C17.5 20.0596 16.9404 19.5 16.25 19.5C15.5596 19.5 15 20.0596 15 20.75C15 21.4404 15.5596 22 16.25 22Z" stroke="#2196F3" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8.25 22C8.94036 22 9.5 21.4404 9.5 20.75C9.5 20.0596 8.94036 19.5 8.25 19.5C7.55964 19.5 7 20.0596 7 20.75C7 21.4404 7.55964 22 8.25 22Z" stroke="#2196F3" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9 8H21" stroke="#2196F3" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

5
assets/icons/slide 2.svg Normal file
View File

@ -0,0 +1,5 @@
<svg width="66" height="22" viewBox="0 0 66 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="8" y="8" width="13" height="6" rx="3" fill="#6A6AE8"/>
<rect x="25" y="8" width="16" height="6" rx="3" fill="#261684"/>
<rect x="45" y="8" width="13" height="6" rx="3" fill="#6A6AE8"/>
</svg>

After

Width:  |  Height:  |  Size: 297 B

5
assets/icons/slide 3.svg Normal file
View File

@ -0,0 +1,5 @@
<svg width="66" height="22" viewBox="0 0 66 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="8" y="8" width="13" height="6" rx="3" fill="#6A6AE8"/>
<rect x="25" y="8" width="13" height="6" rx="3" fill="#6A6AE8"/>
<rect x="42" y="8" width="16" height="6" rx="3" fill="#261684"/>
</svg>

After

Width:  |  Height:  |  Size: 297 B

View File

@ -0,0 +1,5 @@
<svg width="66" height="22" viewBox="0 0 66 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="8" y="8" width="16" height="6" rx="3" fill="#261684"/>
<rect x="28" y="8" width="13" height="6" rx="3" fill="#6A6AE8"/>
<rect x="45" y="8" width="13" height="6" rx="3" fill="#6A6AE8"/>
</svg>

After

Width:  |  Height:  |  Size: 297 B

6
assets/icons/sort.svg Normal file
View File

@ -0,0 +1,6 @@
<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.9375 5.8125H3.3125" stroke="#0E3F66" stroke-width="1.51815" stroke-linecap="round"/>
<path d="M13.625 7.5C14.6605 7.5 15.5 6.66053 15.5 5.625C15.5 4.58947 14.6605 3.75 13.625 3.75C12.5895 3.75 11.75 4.58947 11.75 5.625C11.75 6.66053 12.5895 7.5 13.625 7.5Z" fill="#0E3F66" stroke="#0E3F66" stroke-width="0.8376"/>
<path d="M15.6875 12.5625H9.3125" stroke="#0E3F66" stroke-width="1.51815" stroke-linecap="round"/>
<path d="M4.625 14.25C5.66053 14.25 6.5 13.4105 6.5 12.375C6.5 11.3395 5.66053 10.5 4.625 10.5C3.58947 10.5 2.75 11.3395 2.75 12.375C2.75 13.4105 3.58947 14.25 4.625 14.25Z" fill="#0E3F66" stroke="#0E3F66" stroke-width="0.8376"/>
</svg>

After

Width:  |  Height:  |  Size: 758 B

171
assets/images/Frame.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@ -0,0 +1,6 @@
<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.42 9.1875C17.42 8.6025 17.3675 8.04 17.27 7.5H9.5V10.6913H13.94C13.7488 11.7225 13.1675 12.5963 12.2938 13.1813V15.2512H14.96C16.52 13.815 17.42 11.7 17.42 9.1875Z" fill="#4285F4"/>
<path d="M9.49994 17.25C11.7274 17.25 13.5949 16.5113 14.9599 15.2513L12.2937 13.1813C11.5549 13.6763 10.6099 13.9688 9.49994 13.9688C7.35119 13.9688 5.53244 12.5175 4.88369 10.5675H2.12744V12.705C3.48494 15.4013 6.27494 17.25 9.49994 17.25Z" fill="#34A853"/>
<path d="M4.88375 10.5675C4.71875 10.0725 4.625 9.54376 4.625 9.00001C4.625 8.45626 4.71875 7.92751 4.88375 7.43251V5.29501H2.1275C1.55 6.44466 1.24949 7.71347 1.25 9.00001C1.25 10.3313 1.56875 11.5913 2.1275 12.705L4.88375 10.5675Z" fill="#FBBC05"/>
<path d="M9.49994 4.03125C10.7112 4.03125 11.7987 4.4475 12.6537 5.265L15.0199 2.89875C13.5912 1.5675 11.7237 0.75 9.49994 0.75C6.27494 0.75 3.48494 2.59875 2.12744 5.295L4.88369 7.4325C5.53244 5.4825 7.35119 4.03125 9.49994 4.03125Z" fill="#EA4335"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

14
assets/images/logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 98 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 86 KiB

BIN
assets/images/usa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

34
ios/.gitignore vendored Normal file
View File

@ -0,0 +1,34 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>

View File

@ -0,0 +1 @@
#include "Generated.xcconfig"

View File

@ -0,0 +1 @@
#include "Generated.xcconfig"

View File

@ -0,0 +1,616 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C8086294A63A400263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.lba;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.lba.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.lba.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.lba.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.lba;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.lba;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,13 @@
import Flutter
import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View File

@ -0,0 +1,122 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View File

@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

49
ios/Runner/Info.plist Normal file
View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Lba</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>lba</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"

View File

@ -0,0 +1,12 @@
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}

View File

@ -0,0 +1,26 @@
import 'package:dio/dio.dart';
import 'package:lba/utils/sharedPreferencesKey.dart';
import 'package:lba/utils/sharedPreferencesManger.dart';
class AuthInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options,RequestInterceptorHandler handler) async {
String? token = SharedPreferencesManager().getString(SharedPreferencesKey.token);
if (token!= null) {
options.headers['Authorization'] = 'Bearer $token';
}
super.onRequest(options, handler);
}
}
class DioManager {
static final Dio _dio = Dio();
static Dio get dio{
_dio.interceptors.add(AuthInterceptor());
return _dio;
}
}

260
lib/gen/assets.gen.dart Normal file
View File

@ -0,0 +1,260 @@
/// GENERATED CODE - DO NOT MODIFY BY HAND
/// *****************************************************
/// FlutterGen
/// *****************************************************
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart' as _svg;
import 'package:vector_graphics/vector_graphics.dart' as _vg;
class $AssetsIconsGen {
const $AssetsIconsGen();
/// File path: assets/icons/Next Button.svg
SvgGenImage get nextButton =>
const SvgGenImage('assets/icons/Next Button.svg');
/// File path: assets/icons/arrow-down.svg
SvgGenImage get arrowDown => const SvgGenImage('assets/icons/arrow-down.svg');
/// File path: assets/icons/arrow-left.svg
SvgGenImage get arrowLeft => const SvgGenImage('assets/icons/arrow-left.svg');
/// File path: assets/icons/back.svg
SvgGenImage get back => const SvgGenImage('assets/icons/back.svg');
/// File path: assets/icons/clander.svg
SvgGenImage get clander => const SvgGenImage('assets/icons/clander.svg');
/// File path: assets/icons/location.svg
SvgGenImage get location => const SvgGenImage('assets/icons/location.svg');
/// File path: assets/icons/next.svg
SvgGenImage get next => const SvgGenImage('assets/icons/next.svg');
/// File path: assets/icons/ri_search-2-line.svg
SvgGenImage get riSearch2Line =>
const SvgGenImage('assets/icons/ri_search-2-line.svg');
/// File path: assets/icons/shopping-cart.svg
SvgGenImage get shoppingCart =>
const SvgGenImage('assets/icons/shopping-cart.svg');
/// File path: assets/icons/slide 2.svg
SvgGenImage get slide2 => const SvgGenImage('assets/icons/slide 2.svg');
/// File path: assets/icons/slide 3.svg
SvgGenImage get slide3 => const SvgGenImage('assets/icons/slide 3.svg');
/// File path: assets/icons/slides 1.svg
SvgGenImage get slides1 => const SvgGenImage('assets/icons/slides 1.svg');
/// File path: assets/icons/sort.svg
SvgGenImage get sort => const SvgGenImage('assets/icons/sort.svg');
/// List of all assets
List<SvgGenImage> get values => [
nextButton,
arrowDown,
arrowLeft,
back,
clander,
location,
next,
riSearch2Line,
shoppingCart,
slide2,
slide3,
slides1,
sort,
];
}
class $AssetsImagesGen {
const $AssetsImagesGen();
/// File path: assets/images/Frame.svg
SvgGenImage get frame => const SvgGenImage('assets/images/Frame.svg');
/// File path: assets/images/Google svg.svg
SvgGenImage get googleSvg =>
const SvgGenImage('assets/images/Google svg.svg');
/// File path: assets/images/logo.svg
SvgGenImage get logo => const SvgGenImage('assets/images/logo.svg');
/// File path: assets/images/onboarding3.svg
SvgGenImage get onboarding3 =>
const SvgGenImage('assets/images/onboarding3.svg');
/// File path: assets/images/ounboarding 1.svg
SvgGenImage get ounboarding1 =>
const SvgGenImage('assets/images/ounboarding 1.svg');
/// File path: assets/images/usa.png
AssetGenImage get usa => const AssetGenImage('assets/images/usa.png');
/// List of all assets
List<dynamic> get values => [
frame,
googleSvg,
logo,
onboarding3,
ounboarding1,
usa,
];
}
class Assets {
const Assets._();
static const $AssetsIconsGen icons = $AssetsIconsGen();
static const $AssetsImagesGen images = $AssetsImagesGen();
}
class AssetGenImage {
const AssetGenImage(this._assetName, {this.size, this.flavors = const {}});
final String _assetName;
final Size? size;
final Set<String> flavors;
Image image({
Key? key,
AssetBundle? bundle,
ImageFrameBuilder? frameBuilder,
ImageErrorWidgetBuilder? errorBuilder,
String? semanticLabel,
bool excludeFromSemantics = false,
double? scale,
double? width,
double? height,
Color? color,
Animation<double>? opacity,
BlendMode? colorBlendMode,
BoxFit? fit,
AlignmentGeometry alignment = Alignment.center,
ImageRepeat repeat = ImageRepeat.noRepeat,
Rect? centerSlice,
bool matchTextDirection = false,
bool gaplessPlayback = true,
bool isAntiAlias = false,
String? package,
FilterQuality filterQuality = FilterQuality.medium,
int? cacheWidth,
int? cacheHeight,
}) {
return Image.asset(
_assetName,
key: key,
bundle: bundle,
frameBuilder: frameBuilder,
errorBuilder: errorBuilder,
semanticLabel: semanticLabel,
excludeFromSemantics: excludeFromSemantics,
scale: scale,
width: width,
height: height,
color: color,
opacity: opacity,
colorBlendMode: colorBlendMode,
fit: fit,
alignment: alignment,
repeat: repeat,
centerSlice: centerSlice,
matchTextDirection: matchTextDirection,
gaplessPlayback: gaplessPlayback,
isAntiAlias: isAntiAlias,
package: package,
filterQuality: filterQuality,
cacheWidth: cacheWidth,
cacheHeight: cacheHeight,
);
}
ImageProvider provider({AssetBundle? bundle, String? package}) {
return AssetImage(_assetName, bundle: bundle, package: package);
}
String get path => _assetName;
String get keyName => _assetName;
}
class SvgGenImage {
const SvgGenImage(this._assetName, {this.size, this.flavors = const {}})
: _isVecFormat = false;
const SvgGenImage.vec(this._assetName, {this.size, this.flavors = const {}})
: _isVecFormat = true;
final String _assetName;
final Size? size;
final Set<String> flavors;
final bool _isVecFormat;
_svg.SvgPicture svg({
Key? key,
bool matchTextDirection = false,
AssetBundle? bundle,
String? package,
double? width,
double? height,
BoxFit fit = BoxFit.contain,
AlignmentGeometry alignment = Alignment.center,
bool allowDrawingOutsideViewBox = false,
WidgetBuilder? placeholderBuilder,
String? semanticsLabel,
bool excludeFromSemantics = false,
_svg.SvgTheme? theme,
ColorFilter? colorFilter,
Clip clipBehavior = Clip.hardEdge,
@deprecated Color? color,
@deprecated BlendMode colorBlendMode = BlendMode.srcIn,
@deprecated bool cacheColorFilter = false,
}) {
final _svg.BytesLoader loader;
if (_isVecFormat) {
loader = _vg.AssetBytesLoader(
_assetName,
assetBundle: bundle,
packageName: package,
);
} else {
loader = _svg.SvgAssetLoader(
_assetName,
assetBundle: bundle,
packageName: package,
theme: theme,
);
}
return _svg.SvgPicture(
loader,
key: key,
matchTextDirection: matchTextDirection,
width: width,
height: height,
fit: fit,
alignment: alignment,
allowDrawingOutsideViewBox: allowDrawingOutsideViewBox,
placeholderBuilder: placeholderBuilder,
semanticsLabel: semanticsLabel,
excludeFromSemantics: excludeFromSemantics,
colorFilter:
colorFilter ??
(color == null ? null : ColorFilter.mode(color, colorBlendMode)),
clipBehavior: clipBehavior,
cacheColorFilter: cacheColorFilter,
);
}
String get path => _assetName;
String get keyName => _assetName;
}

34
lib/main.dart Normal file
View File

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lba/screens/auth/onboarding.dart';
import 'package:lba/screens/auth/cubit/auth_cubit.dart';
void main() {
runApp(
BlocProvider(
create: (context) => AuthCubit(),
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'LBA',
theme: ThemeData(
primaryColor: const Color.fromARGB(255, 14, 63, 102),
buttonTheme: const ButtonThemeData(
buttonColor: Color.fromARGB(255, 14, 63, 102),
),
appBarTheme: const AppBarTheme(
backgroundColor: Color.fromARGB(255, 14, 63, 102),
),
),
home: const OnboardingScreen(),
);
}
}

View File

@ -0,0 +1,40 @@
import 'package:bloc/bloc.dart';
import 'package:dio/dio.dart';
import 'package:meta/meta.dart';
part 'auth_state.dart';
class AuthCubit extends Cubit<AuthState> {
AuthCubit() : super(AuthInitial());
final Dio _dio = Dio(BaseOptions(
connectTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 30),
));
Future<void> sendOTP(String phoneNumber) async {
emit(AuthLoading());
try {
final response = await _dio.post(
'https://api-gateway.liara.run/auth/otp/generate',
data: {'userId': phoneNumber},
);
print(response.toString());
if (response.statusCode == 200 || response.statusCode == 201) {
if (response.data['success'] == true) {
emit(AuthSuccess(phoneNumber: phoneNumber));
print(response.data.toString());
} else {
emit(AuthError('Failed to send OTP'));
}
} else {
emit(AuthError('Server error: ${response.statusCode}'));
}
} on DioException catch (e) {
emit(AuthError('Connection error: ${e.message}'));
} catch (e) {
emit(AuthError('Unexpected error occurred'));
}
}
}

View File

@ -0,0 +1,18 @@
part of 'auth_cubit.dart';
@immutable
sealed class AuthState {}
final class AuthInitial extends AuthState {}
final class AuthLoading extends AuthState {}
final class AuthSuccess extends AuthState {
final String phoneNumber;
AuthSuccess({required this.phoneNumber});
}
final class AuthError extends AuthState {
final String message;
AuthError(this.message);
}

211
lib/screens/auth/login.dart Normal file
View File

@ -0,0 +1,211 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:lba/gen/assets.gen.dart';
import 'package:lba/screens/auth/cubit/auth_cubit.dart';
import 'package:lba/screens/auth/otpVerifcation.dart';
import 'package:lba/widgets/loginButton.dart';
class Login extends StatefulWidget {
const Login({super.key});
@override
State<Login> createState() => _LoginState();
}
class _LoginState extends State<Login> {
final TextEditingController phoneController = TextEditingController();
final List<Map<String, String>> flagList = [
{"image": "assets/images/usa.png", "code": "+1"},
{"image": "assets/images/usa.png", "code": "+98"},
{"image": "assets/images/usa.png", "code": "+44"},
];
int selectedIndex = 0;
bool keepSignedIn = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 48),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Padding(
padding: const EdgeInsets.only(top: 50),
child: SvgPicture.asset(Assets.images.logo.path),
),
),
const SizedBox(height: 24),
const Text(
"Login",
style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text("Please enter your phone number"),
const SizedBox(height: 25),
TextField(
controller: phoneController,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
labelText: "Phone Number",
labelStyle: const TextStyle(
color: Color.fromARGB(255, 61, 61, 61),
),
hintText: "Phone Number",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Color.fromARGB(255, 14, 63, 102),
width: 2,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Color.fromARGB(255, 14, 63, 102),
),
),
prefixIcon: Padding(
padding: const EdgeInsets.only(left: 10, right: 5),
child: DropdownButtonHideUnderline(
child: DropdownButton<int>(
value: selectedIndex,
items: List.generate(flagList.length, (index) {
return DropdownMenuItem<int>(
value: index,
child: Row(
children: [
Image.asset(
flagList[index]["image"]!,
width: 24,
height: 24,
),
const SizedBox(width: 6),
Text(
flagList[index]["code"]!,
style: const TextStyle(fontSize: 14),
),
],
),
);
}),
onChanged: (value) {
setState(() {
selectedIndex = value!;
});
},
),
),
),
),
),
const SizedBox(height: 16),
Row(
children: [
Checkbox(
value: keepSignedIn,
activeColor: const Color.fromARGB(255, 14, 63, 102),
onChanged: (bool? value) {
setState(() {
keepSignedIn = value ?? false;
});
},
),
const Text("Keep me signed in"),
],
),
const SizedBox(height: 16),
BlocConsumer<AuthCubit, AuthState>(
listener: (context, state) {
if (state is AuthSuccess) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
OTPverifaction(phoneNumber: phoneController.text),
),
);
} else if (state is AuthError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: Colors.red,
content: Text(state.message ?? "An error occurred"),
),
);
}
},
builder: (context, state) {
if (state is AuthLoading) {
return const Center(child: CircularProgressIndicator());
}
return Column(
children: [
SizedBox(
width: double.infinity,
height: 48,
child: LogInButton(
text: "Get OTP",
onPressed: () {
context.read<AuthCubit>().sendOTP(
"${flagList[selectedIndex]["code"]}${phoneController.text}",
);
},
),
),
const SizedBox(height: 32),
Row(
children: [
const Expanded(
child: Divider(thickness: 1, color: Colors.grey),
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
"Or continue with",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
const Expanded(
child: Divider(thickness: 1, color: Colors.grey),
),
],
),
const SizedBox(height: 32),
SizedBox(
width: double.infinity,
height: 48,
child: OutlinedButton.icon(
icon: SvgPicture.asset(Assets.images.googleSvg.path),
label: const Text(
"Login with google",
style: TextStyle(color: Colors.black),
),
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Colors.grey),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
),
onPressed: () {},
),
),
],
);
},
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,106 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:lba/gen/assets.gen.dart';
import 'package:lba/screens/auth/login.dart';
class OnboardingScreen extends StatefulWidget {
const OnboardingScreen({super.key});
@override
State<OnboardingScreen> createState() => _OnboardingScreenState();
}
class _OnboardingScreenState extends State<OnboardingScreen> {
int currentIndex = 0;
final List<String> imageAssets = [
Assets.images.ounboarding1.path,
Assets.images.frame.path,
Assets.images.onboarding3.path,
];
final List<String> slides = [
Assets.icons.slides1.path,
Assets.icons.slide2.path,
Assets.icons.slide3.path,
];
void _next() {
if (currentIndex < imageAssets.length - 1) {
setState(() {
currentIndex++;
});
} else {
Navigator.push(context, MaterialPageRoute(builder: (context) => Login(),));
}
}
void _back() {
if (currentIndex > 0) {
setState(() {
currentIndex--;
});
}
}
@override
Widget build(BuildContext context) {
var sizeScreen = MediaQuery.of(context).size;
return Scaffold(
body: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(50, 150, 50, 100),
child: SvgPicture.asset(imageAssets[currentIndex]),
),
Padding(
padding: EdgeInsets.fromLTRB(sizeScreen.width/15, 10, sizeScreen.width/15, 5),
child: Row(
children: [
Text(
"Proxibuy Geofencing marketing",
style: TextStyle(fontWeight: FontWeight.w900),
textDirection: TextDirection.ltr,
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(sizeScreen.width/15, 10, sizeScreen.width/15, sizeScreen.height/40),
child: Text(
'"Join the app to discover exclusive discounts and special offers in specific areas around you for a smarter shopping experience!"',
style: TextStyle(fontWeight: FontWeight.w500,color: const Color.fromARGB(255, 88, 88, 88)),
),
),
const SizedBox(height: 50),
Padding(
padding: EdgeInsets.fromLTRB(sizeScreen.width/15, 10, sizeScreen.width/15, sizeScreen.height/40),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(slides[currentIndex]),
Row(
children: [
if (currentIndex > 0)
GestureDetector(
onTap: _back,
child: SvgPicture.asset(Assets.icons.arrowLeft.path),
),
const SizedBox(width: 8),
GestureDetector(
onTap: _next,
child: SvgPicture.asset(Assets.icons.next.path),
),
],
)
],
),
)
],
),
);
}
}

View File

@ -0,0 +1,177 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:lba/gen/assets.gen.dart';
import 'package:lba/screens/auth/userInfo.dart';
import 'package:lba/widgets/loginButton.dart';
class OTPverifaction extends StatefulWidget {
final String phoneNumber;
const OTPverifaction({super.key, required this.phoneNumber});
@override
State<OTPverifaction> createState() => _LoginState();
}
class _LoginState extends State<OTPverifaction> {
final List<FocusNode> _focusNodes = List.generate(5, (_) => FocusNode());
final List<TextEditingController> _controllers = List.generate(5, (_) => TextEditingController());
Timer? _timer;
int _remainingSeconds = 600;
bool _canResend = false;
@override
void initState() {
super.initState();
_startTimer();
}
void _startTimer() {
_timer?.cancel();
_remainingSeconds = 600;
_canResend = false;
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (_remainingSeconds == 0) {
setState(() {
_canResend = true;
timer.cancel();
});
} else {
setState(() {
_remainingSeconds--;
});
}
});
}
String _formatTime(int seconds) {
final minutes = (seconds ~/ 60).toString().padLeft(2, '0');
final secs = (seconds % 60).toString().padLeft(2, '0');
return "$minutes:$secs";
}
@override
void dispose() {
for (final node in _focusNodes) {
node.dispose();
}
for (final controller in _controllers) {
controller.dispose();
}
_timer?.cancel();
super.dispose();
}
Widget _buildOTPFields() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(5, (index) {
return SizedBox(
width: 50,
child: TextField(
controller: _controllers[index],
focusNode: _focusNodes[index],
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
maxLength: 1,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
decoration: InputDecoration(
counterText: '',
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.grey),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Color.fromARGB(255, 14, 63, 102)),
),
),
onChanged: (value) {
if (value.length == 1 && index < 4) {
FocusScope.of(context).requestFocus(_focusNodes[index + 1]);
}
},
),
);
}),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
IconButton(
icon: SvgPicture.asset(Assets.icons.back.path,),
onPressed: () => Navigator.pop(context),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
Center(child: SvgPicture.asset(Assets.images.logo.path)),
const SizedBox(height: 24),
const Text("OTP Verification", style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
const Text("Enter the verification code we just sent to your device."),
const SizedBox(height: 25),
_buildOTPFields(),
const SizedBox(height: 70),
SizedBox(
width: double.infinity,
height: 48,
child: LogInButton(text: "Verify",onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => UserInfo(),));
},)
),
const SizedBox(height: 40),
Center(
child: Column(
children: [
Row(
children: [
const Expanded(
child: Divider(thickness: 1, color: Colors.grey),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: Text("Resend OTP in ${_formatTime(_remainingSeconds)}",style: TextStyle(fontWeight: FontWeight.bold),),
),
const Expanded(
child: Divider(thickness: 1, color: Colors.grey),
),
],
),
const SizedBox(height: 8),
GestureDetector(
onTap: _canResend ? () => _startTimer() : null,
child: Text(
"Resend Code",
style: TextStyle(
fontSize: 16,
color: _canResend ? const Color.fromARGB(255, 0, 0, 0) : Colors.grey,
),
),
),
],
),
),
],
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,376 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:lba/gen/assets.gen.dart';
import 'package:lba/screens/nearby/nearby.dart';
import 'package:lba/widgets/interestsUserInfo.dart';
import 'package:lba/widgets/loginButton.dart';
class UserInfo extends StatefulWidget {
const UserInfo({super.key});
@override
State<UserInfo> createState() => _UserInfoState();
}
class _UserInfoState extends State<UserInfo> {
DateTime? selectedDate;
String? selectedGender;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
IconButton(
icon: SvgPicture.asset(Assets.icons.back.path),
onPressed: () => Navigator.pop(context),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24),
child: Center(child: SvgPicture.asset(Assets.images.logo.path)),
),
const SizedBox(height: 24),
const Padding(
padding: EdgeInsets.fromLTRB(25, 0, 25, 20),
child: Text(
"what do you like to be called in this application?",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 117, 117, 117),
),
),
),
const Padding(
padding: EdgeInsets.fromLTRB(25, 0, 25, 0),
child: TextField(
decoration: InputDecoration(
counterText: '',
hintText: "Enter here...",
hintStyle: TextStyle(fontWeight: FontWeight.w500, color: Colors.grey),
filled: true,
fillColor: Color.fromARGB(133, 250, 250, 250),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
borderSide: BorderSide(color: Color.fromARGB(255, 14, 63, 102)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
borderSide: BorderSide(color: Colors.grey, width: 2),
),
),
),
),
const SizedBox(height: 24),
const Padding(
padding: EdgeInsets.fromLTRB(25, 0, 25, 10),
child: Text(
"Gender",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 117, 117, 117),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Wrap(
spacing: 10,
children: [
ChoiceChip(
label: const Text("Male"),
selected: selectedGender == "Male",
onSelected: (_) => setState(() => selectedGender = "Male"),
),
ChoiceChip(
label: const Text("Female"),
selected: selectedGender == "Female",
onSelected: (_) => setState(() => selectedGender = "Female"),
),
ChoiceChip(
label: const Text("Prefer not to say"),
selected: selectedGender == "Prefer not to say",
onSelected: (_) => setState(() => selectedGender = "Prefer not to say"),
),
],
),
),
const SizedBox(height: 24),
const Padding(
padding: EdgeInsets.fromLTRB(25, 0, 25, 15),
child: Text(
"Birth Date?",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 117, 117, 117),
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(25, 0, 25, 0),
child: TextField(
readOnly: true,
decoration: InputDecoration(
hintText: selectedDate != null
? "${selectedDate!.month}/${selectedDate!.day}/${selectedDate!.year}"
: "mm/dd/yyyy",
hintStyle: const TextStyle(fontWeight: FontWeight.w500, color: Colors.grey),
filled: true,
fillColor: const Color.fromARGB(133, 250, 250, 250),
enabledBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
borderSide: BorderSide(color: Color.fromARGB(255, 14, 63, 102)),
),
focusedBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
borderSide: BorderSide(color: Colors.grey, width: 2),
),
suffixIcon: IconButton(
icon: SvgPicture.asset(Assets.icons.clander.path),
onPressed: () async {
final result = await showModalBottomSheet<DateTime>(
context: context,
builder: (_) => const _DatePickerSheet(),
);
if (result != null) {
setState(() {
selectedDate = result;
});
}
},
),
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(25, 25, 25, 10),
child: Text(
"Interests / Preferences",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 117, 117, 117),
),
),
),
Interests(icon: Assets.icons.shoppingCart.path,title: "Shopping & Retail",options: ["Fashion & Clothing","Electronics & Gadgets","Shoes & Accessories"],),
SizedBox(height: 30,),
Center(child: SizedBox(
width: 300,
child: LogInButton(text: "Submit", onPressed:() {
Navigator.push(context, MaterialPageRoute(builder:
(context) => Nearby(),
));
},))),
],
),
),
);
}
}
class _DatePickerSheet extends StatefulWidget {
const _DatePickerSheet();
@override
State<_DatePickerSheet> createState() => _DatePickerSheetState();
}
class _DatePickerSheetState extends State<_DatePickerSheet> {
late DateTime now;
late int selectedYear;
late int selectedMonth;
int? selectedDay;
late final List<int> years;
final List<String> months = [
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
];
@override
void initState() {
super.initState();
now = DateTime.now();
selectedYear = now.year;
selectedMonth = now.month;
years = List.generate(100, (index) => now.year - index);
}
List<DateTime?> getCalendarDays() {
final firstDayOfMonth = DateTime(selectedYear, selectedMonth, 1);
final lastDayOfMonth = DateTime(selectedYear, selectedMonth + 1, 0);
final daysInMonth = lastDayOfMonth.day;
List<DateTime?> days = [];
// Add empty days for alignment
for (int i = 0; i < firstDayOfMonth.weekday - 1; i++) {
days.add(null);
}
// Add actual days
for (int day = 1; day <= daysInMonth; day++) {
days.add(DateTime(selectedYear, selectedMonth, day));
}
return days;
}
@override
Widget build(BuildContext context) {
final days = getCalendarDays();
final weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
return Container(
padding: const EdgeInsets.all(16),
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.7,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Month and year selection
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Month selection
SizedBox(
width: 200,
child: DropdownButton<int>(
value: selectedMonth,
isExpanded: true,
items: List.generate(12, (index) {
return DropdownMenuItem(
value: index + 1,
child: Text(months[index]),
);
}),
onChanged: (value) {
setState(() {
selectedMonth = value!;
selectedDay = null;
});
},
),
),
// Year selection
SizedBox(
width: 120,
child: DropdownButton<int>(
value: selectedYear,
isExpanded: true,
items: years.map((year) {
return DropdownMenuItem(
value: year,
child: Text(year.toString()),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedYear = value!;
selectedDay = null;
});
},
),
),
],
),
const SizedBox(height: 16),
// Weekday headers
Row(
children: weekdays.map((day) {
return Expanded(
child: Center(
child: Text(
day,
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.grey,
),
),
),
);
}).toList(),
),
const SizedBox(height: 8),
// Calendar grid
Expanded(
child: GridView.count(
crossAxisCount: 7,
shrinkWrap: true,
children: days.map((date) {
return date == null
? const SizedBox.shrink()
: InkWell(
onTap: () => setState(() => selectedDay = date.day),
child: Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: selectedDay == date.day
? Colors.blue
: Colors.transparent,
shape: BoxShape.circle,
),
child: Center(
child: Text(
date.day.toString(),
style: TextStyle(
color: selectedDay == date.day
? Colors.white
: Colors.black,
fontWeight: selectedDay == date.day
? FontWeight.bold
: FontWeight.normal,
),
),
),
),
);
}).toList(),
),
),
const SizedBox(height: 16),
// Confirm button
ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size(double.infinity, 50),
backgroundColor: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
onPressed: () {
if (selectedDay != null) {
Navigator.pop(
context,
DateTime(selectedYear, selectedMonth, selectedDay!),
);
}
},
child: const Text(
"Confirm",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
],
),
);
}
}

View File

@ -0,0 +1,209 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:lba/gen/assets.gen.dart';
class Nearby extends StatefulWidget {
const Nearby({super.key});
@override
State<Nearby> createState() => _NearbyState();
}
class _NearbyState extends State<Nearby> {
int selectedIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 70,
shadowColor: Colors.grey,
elevation: 2,
automaticallyImplyLeading: false,
title: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Row(
children: [
Expanded(
child: SizedBox(
height: 40,
child: TextField(
decoration: InputDecoration(
hintText: 'What are you looking for?',
hintStyle: const TextStyle(
color: Colors.grey,
fontSize: 13,
),
prefixIcon: Padding(
padding: const EdgeInsets.all(10.0),
child: SvgPicture.asset(
Assets.icons.riSearch2Line.path,
width: 18,
height: 18,
),
),
filled: true,
fillColor: const Color.fromARGB(255, 248, 248, 248),
contentPadding:
const EdgeInsets.symmetric(horizontal: 16.0),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0),
borderSide: const BorderSide(
color: Color.fromARGB(255, 14, 63, 102),
width: 2.0,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0),
borderSide: const BorderSide(
color: Color.fromARGB(255, 14, 63, 102),
width: 1.0,
),
),
),
),
),
),
const SizedBox(width: 10),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: const Color.fromARGB(255, 14, 63, 102),
width: 1.5,
),
),
child: IconButton(
icon: SvgPicture.asset(Assets.icons.sort.path),
onPressed: () {},
padding: const EdgeInsets.all(8),
),
),
const SizedBox(width: 8),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: const Color.fromARGB(255, 14, 63, 102),
width: 1.5,
),
),
child: IconButton(
icon: SvgPicture.asset(Assets.icons.location.path),
onPressed: () {},
padding: const EdgeInsets.all(8),
),
),
],
),
],
),
),
backgroundColor: Colors.white,
),
body: Center(
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 20, 0, 0),
child: SizedBox(
width: 340,
height: 60,
child: Stack(
clipBehavior: Clip.none,
children: [
Positioned(
left: selectedIndex==0?10:0,
child: buildToggleButton(
text: 'list',
isSelected: selectedIndex == 1,
onTap: () => setState(() => selectedIndex = 1),
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(12),
bottomLeft: const Radius.circular(12),
topRight: selectedIndex == 1
? const Radius.circular(12)
: Radius.zero,
bottomRight: selectedIndex == 1
? const Radius.circular(12)
: Radius.zero,
),
),
),
Positioned(
right: selectedIndex==1?1:0,
child: buildToggleButton(
text: 'map',
isSelected: selectedIndex == 0,
onTap: () => setState(() => selectedIndex = 0),
borderRadius: BorderRadius.only(
topRight: const Radius.circular(12),
bottomRight: const Radius.circular(12),
topLeft: selectedIndex == 0
? const Radius.circular(12)
: Radius.zero,
bottomLeft: selectedIndex == 0
? const Radius.circular(12)
: Radius.zero,
),
),
),
],
),
),
),
],
),
),
);
}
Widget buildToggleButton({
required String text,
required bool isSelected,
required VoidCallback onTap,
required BorderRadius borderRadius,
}) {
return GestureDetector(
onTap: onTap,
child: Container(
width: 170,
height: 60,
decoration: BoxDecoration(
borderRadius: borderRadius,
color: isSelected
? const Color.fromARGB(255, 14, 63, 102)
: const Color.fromARGB(255, 234, 234, 233),
boxShadow: isSelected
? [
BoxShadow(
color: Colors.black.withOpacity(0.2),
spreadRadius: 1,
blurRadius: 4,
offset: const Offset(0, 2),
)
]
: null,
),
alignment: Alignment.center,
child: Row(
children: [
Text(
text,
style: TextStyle(
color: isSelected ? Colors.white : Colors.black87,
fontWeight: FontWeight.bold,
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,3 @@
class SharedPreferencesKey {
static const String token = 'token';
}

View File

@ -0,0 +1,49 @@
import 'package:shared_preferences/shared_preferences.dart';
class SharedPreferencesManager{
SharedPreferences? _preferences;
SharedPreferencesManager._privateConstructor();
static final SharedPreferencesManager _instance = SharedPreferencesManager._privateConstructor();
factory SharedPreferencesManager(){
return _instance;
}
Future<void> init() async{
_preferences = await SharedPreferences.getInstance();
}
Future<void> saveString(String key , String value) async{
await _preferences?.setString(key, value);
}
Future<void> saveInt(String key,int value) async{
await _preferences?.setInt(key, value);
}
Future<void> saveBool(String key,bool value) async{
await _preferences?.setBool(key, value);
}
String? getString(String key){
return _preferences?.getString(key);
}
int? getInt(String key){
return _preferences?.getInt(key);
}
bool? getBool(String key){
return _preferences?.getBool(key);
}
Future<void> remove(String key) async{
await _preferences?.remove(key);
}
}

View File

@ -0,0 +1,98 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:lba/gen/assets.gen.dart';
class Interests extends StatefulWidget {
final String icon;
final String title;
final List<String> options;
const Interests({
super.key,
required this.icon,
required this.title,
required this.options,
});
@override
State<Interests> createState() => _InterestsState();
}
class _InterestsState extends State<Interests> {
bool _isExpanded = false;
List<String> _selectedOptions = [];
void _onOptionToggled(String option) {
setState(() {
if (_selectedOptions.contains(option)) {
_selectedOptions.remove(option);
} else {
_selectedOptions.add(option);
}
});
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(24, 8, 24, 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () {
setState(() {
_isExpanded = !_isExpanded;
});
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
SvgPicture.asset(widget.icon),
const SizedBox(width: 5),
Text(
widget.title,
style: const TextStyle(fontWeight: FontWeight.w500),
),
],
),
SvgPicture.asset(Assets.icons.arrowDown.path)
],
),
),
if (_isExpanded)
Padding(
padding: const EdgeInsets.all(8.0),
child: Wrap(
spacing: 10,
runSpacing: 10,
children: widget.options.map((option) {
final isSelected = _selectedOptions.contains(option);
return GestureDetector(
onTap: () => _onOptionToggled(option),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
decoration: BoxDecoration(
color: isSelected ? Colors.blue : const Color.fromARGB(0, 53, 49, 49),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: isSelected?const Color.fromARGB(0, 0, 0, 0):Colors.grey),
),
child: Text(
option,
style: TextStyle(
color: isSelected ? Colors.black : Colors.grey,
fontWeight: FontWeight.w500
),
),
),
);
}).toList(),
),
)
],
),
);
}
}

View File

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
class LogInButton extends StatelessWidget {
final String text;
final VoidCallback onPressed;
const LogInButton({
super.key,
required this.text,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color.fromARGB(255, 30, 137, 221),
minimumSize: const Size(double.infinity, 48),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
),
onPressed: onPressed,
child: Text(
text,
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
);
}
}

1
linux/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
flutter/ephemeral

128
linux/CMakeLists.txt Normal file
View File

@ -0,0 +1,128 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.13)
project(runner LANGUAGES CXX)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "lba")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "com.example.lba")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(SET CMP0063 NEW)
# Load bundled libraries from the lib/ directory relative to the binary.
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
# Root filesystem for cross-building.
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()
# Define build configuration options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
# Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14)
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction()
# Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
# Application build; see runner/CMakeLists.txt.
add_subdirectory("runner")
# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble)
# Only the install-generated bundle's copy of the executable will launch
# correctly, since the resources must in the right relative locations. To avoid
# people trying to run the unbundled copy, put it in a subdirectory instead of
# the default top-level location.
set_target_properties(${BINARY_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
)
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# By default, "installing" just makes a relocatable bundle in the build
# directory.
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
# Start with a clean build bundle directory every time.
install(CODE "
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
" COMPONENT Runtime)
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
install(FILES "${bundled_library}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endforeach(bundled_library)
# Copy the native assets provided by the build.dart from all packages.
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only.
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()

View File

@ -0,0 +1,88 @@
# This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.10)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146.
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
# which isn't available in 3.10.
function(list_prepend LIST_NAME PREFIX)
set(NEW_LIST "")
foreach(element ${${LIST_NAME}})
list(APPEND NEW_LIST "${PREFIX}${element}")
endforeach(element)
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
endfunction()
# === Flutter Library ===
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
# Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"fl_basic_message_channel.h"
"fl_binary_codec.h"
"fl_binary_messenger.h"
"fl_dart_project.h"
"fl_engine.h"
"fl_json_message_codec.h"
"fl_json_method_codec.h"
"fl_message_codec.h"
"fl_method_call.h"
"fl_method_channel.h"
"fl_method_codec.h"
"fl_method_response.h"
"fl_plugin_registrar.h"
"fl_plugin_registry.h"
"fl_standard_message_codec.h"
"fl_standard_method_codec.h"
"fl_string_codec.h"
"fl_value.h"
"fl_view.h"
"flutter_linux.h"
)
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
target_link_libraries(flutter INTERFACE
PkgConfig::GTK
PkgConfig::GLIB
PkgConfig::GIO
)
add_dependencies(flutter flutter_assemble)
# === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the
# flutter tool.
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/_phony_
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
)

View File

@ -0,0 +1,11 @@
//
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
void fl_register_plugins(FlPluginRegistry* registry) {
}

View File

@ -0,0 +1,15 @@
//
// Generated file. Do not edit.
//
// clang-format off
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter_linux/flutter_linux.h>
// Registers Flutter plugins.
void fl_register_plugins(FlPluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_

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