ci: add keystore/key.properties to repo, fix NDK version, remove duplicate build.gradle
Build Release AAB / build (push) Failing after 6m58s

This commit is contained in:
andrew committed 2026-09-17 08:26:27 +07:00
1 parent e4c32f9def
commit 9239c77106
125 files changed
+5540 -5285

No files matched your search

+2 -17
View File
@@ -35,21 +35,6 @@ jobs:
- name: Run tests
run: flutter test
- name: Decode keystore
if: env.KEYSTORE_BASE64 != ''
run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > siab-release.keystore
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
- name: Create key.properties
run: |
cat > android/key.properties <<EOF
storePassword=Store_sc4l3
keyPassword=Store_sc4l3
keyAlias=siab
storeFile=../siab-release.keystore
EOF
- name: Build App Bundle
run: |
flutter build appbundle \
@@ -58,8 +43,8 @@ jobs:
--split-debug-info=build/debug-info \
--dart-define=SIAB_DEVICE_NAME=SIAB
env:
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
KEYSTORE_PASSWORD: Store_sc4l3
KEY_PASSWORD: Store_sc4l3
- name: Upload AAB artifact
uses: actions/upload-artifact@v4
-5
View File
@@ -42,8 +42,3 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
# Keystore and signing
*.keystore
*.jks
android/key.properties
+45 -45
View File
@@ -1,45 +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: "adc901062556672b4138e18a4dc62a4be8f4b3c2"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
- platform: android
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
- platform: ios
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
- platform: linux
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
- platform: macos
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
- platform: web
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
- platform: windows
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
# 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'
# 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: "adc901062556672b4138e18a4dc62a4be8f4b3c2"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
- platform: android
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
- platform: ios
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
- platform: linux
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
- platform: macos
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
- platform: web
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
- platform: windows
create_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
base_revision: adc901062556672b4138e18a4dc62a4be8f4b3c2
# 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'
+93 -93
View File
@@ -1,93 +1,93 @@
# Android Setup Guide
## Option 1: Use Physical Android Device (Recommended)
### Steps:
1. **Enable Developer Options on your Android device:**
- Go to Settings > About Phone
- Tap "Build Number" 7 times
- Go back to Settings > Developer Options
- Enable "USB Debugging"
2. **Connect device via USB:**
```bash
# Check if device is detected
adb devices
```
3. **Run the app:**
```bash
cd flutter_siab_app
flutter run
```
## Option 2: Use Android Emulator
### Install Android Studio:
1. Download Android Studio: https://developer.android.com/studio
2. Install Android SDK and create an emulator:
- Open Android Studio
- Tools > Device Manager
- Create Virtual Device
- Choose a device (e.g., Pixel 5)
- Download a system image (API 30+ recommended)
- Finish setup
3. **Start the emulator:**
```bash
# List available emulators
flutter emulators
# Launch emulator (replace with your emulator name)
flutter emulators --launch <emulator_id>
```
4. **Run the app:**
```bash
cd flutter_siab_app
flutter run
```
## Option 3: Build APK and Install Manually
If you can't use USB debugging, build an APK:
```bash
cd flutter_siab_app
flutter build apk --release
```
The APK will be at: `build/app/outputs/flutter-apk/app-release.apk`
Transfer to your Android device and install it.
## Troubleshooting
### "No devices found"
- Ensure USB debugging is enabled
- Try different USB cable/port
- Run `adb devices` to verify connection
- On Linux, you may need to add udev rules
### "Permission denied"
- Check USB debugging authorization on device
- Try `adb kill-server && adb start-server`
### Bluetooth not working on emulator
- Physical devices are recommended for Bluetooth testing
- Some emulators don't support Bluetooth BLE
- Use a real Android device for best results
## Required Permissions
The app needs these permissions (already configured):
- Bluetooth
- Bluetooth Admin
- Bluetooth Scan
- Bluetooth Connect
- Location (required for BLE scanning on Android 12+)
Make sure to grant all permissions when the app requests them.
# Android Setup Guide
## Option 1: Use Physical Android Device (Recommended)
### Steps:
1. **Enable Developer Options on your Android device:**
- Go to Settings > About Phone
- Tap "Build Number" 7 times
- Go back to Settings > Developer Options
- Enable "USB Debugging"
2. **Connect device via USB:**
```bash
# Check if device is detected
adb devices
```
3. **Run the app:**
```bash
cd flutter_siab_app
flutter run
```
## Option 2: Use Android Emulator
### Install Android Studio:
1. Download Android Studio: https://developer.android.com/studio
2. Install Android SDK and create an emulator:
- Open Android Studio
- Tools > Device Manager
- Create Virtual Device
- Choose a device (e.g., Pixel 5)
- Download a system image (API 30+ recommended)
- Finish setup
3. **Start the emulator:**
```bash
# List available emulators
flutter emulators
# Launch emulator (replace with your emulator name)
flutter emulators --launch <emulator_id>
```
4. **Run the app:**
```bash
cd flutter_siab_app
flutter run
```
## Option 3: Build APK and Install Manually
If you can't use USB debugging, build an APK:
```bash
cd flutter_siab_app
flutter build apk --release
```
The APK will be at: `build/app/outputs/flutter-apk/app-release.apk`
Transfer to your Android device and install it.
## Troubleshooting
### "No devices found"
- Ensure USB debugging is enabled
- Try different USB cable/port
- Run `adb devices` to verify connection
- On Linux, you may need to add udev rules
### "Permission denied"
- Check USB debugging authorization on device
- Try `adb kill-server && adb start-server`
### Bluetooth not working on emulator
- Physical devices are recommended for Bluetooth testing
- Some emulators don't support Bluetooth BLE
- Use a real Android device for best results
## Required Permissions
The app needs these permissions (already configured):
- Bluetooth
- Bluetooth Admin
- Bluetooth Scan
- Bluetooth Connect
- Location (required for BLE scanning on Android 12+)
Make sure to grant all permissions when the app requests them.
+78 -78
View File
@@ -1,78 +1,78 @@
# Quick Start Guide
## Prerequisites
1. Install Flutter: https://flutter.dev/docs/get-started/install
2. Install Android Studio or VS Code with Flutter extensions
3. Enable developer options on your Android device
## Setup Steps
1. **Navigate to the app directory:**
```bash
cd flutter_siab_app
```
2. **Get Flutter dependencies:**
```bash
flutter pub get
```
3. **Connect your Android device** (USB debugging enabled) or start an emulator
4. **Run the app:**
```bash
flutter run
```
## First Run
1. **Grant Permissions:**
- The app will request Bluetooth and Location permissions
- Grant all permissions (Location is required for BLE scanning on Android)
2. **Connect to SIAB Device:**
- Tap the blue floating action button (FAB) at bottom right
- App will scan for devices named "SIAB"
- Once found, it will connect automatically
- If no data arrives, it will try common start commands
3. **View Data:**
- Streamed data packets appear in real-time
- Tap any packet to see detailed information
- View statistics at the top
## Features
- ✅ One-tap connect/disconnect
- ✅ Real-time data streaming
- ✅ Detailed packet information
- ✅ Statistics (count, rate, duration)
- ✅ Automatic start command detection
- ✅ Clean, Material Design UI
## Troubleshooting
### "No devices found"
- Ensure SIAB device is powered on
- Check device name matches "SIAB" (case-insensitive)
- Verify Bluetooth is enabled on both devices
### "Permission denied"
- Go to Android Settings > Apps > SIAB Bluetooth > Permissions
- Enable Location permission (required for BLE)
### "No data received"
- App automatically tries start commands
- Check device documentation for correct command
- Device may need specific initialization sequence
## Building APK
To build a release APK:
```bash
flutter build apk --release
```
APK location: `build/app/outputs/flutter-apk/app-release.apk`
# Quick Start Guide
## Prerequisites
1. Install Flutter: https://flutter.dev/docs/get-started/install
2. Install Android Studio or VS Code with Flutter extensions
3. Enable developer options on your Android device
## Setup Steps
1. **Navigate to the app directory:**
```bash
cd flutter_siab_app
```
2. **Get Flutter dependencies:**
```bash
flutter pub get
```
3. **Connect your Android device** (USB debugging enabled) or start an emulator
4. **Run the app:**
```bash
flutter run
```
## First Run
1. **Grant Permissions:**
- The app will request Bluetooth and Location permissions
- Grant all permissions (Location is required for BLE scanning on Android)
2. **Connect to SIAB Device:**
- Tap the blue floating action button (FAB) at bottom right
- App will scan for devices named "SIAB"
- Once found, it will connect automatically
- If no data arrives, it will try common start commands
3. **View Data:**
- Streamed data packets appear in real-time
- Tap any packet to see detailed information
- View statistics at the top
## Features
- ✅ One-tap connect/disconnect
- ✅ Real-time data streaming
- ✅ Detailed packet information
- ✅ Statistics (count, rate, duration)
- ✅ Automatic start command detection
- ✅ Clean, Material Design UI
## Troubleshooting
### "No devices found"
- Ensure SIAB device is powered on
- Check device name matches "SIAB" (case-insensitive)
- Verify Bluetooth is enabled on both devices
### "Permission denied"
- Go to Android Settings > Apps > SIAB Bluetooth > Permissions
- Enable Location permission (required for BLE)
### "No data received"
- App automatically tries start commands
- Check device documentation for correct command
- Device may need specific initialization sequence
## Building APK
To build a release APK:
```bash
flutter build apk --release
```
APK location: `build/app/outputs/flutter-apk/app-release.apk`
+37 -28
View File
@@ -1,28 +1,37 @@
# 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
# 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.
analyzer:
exclude:
- build/**
- android/**
- ios/**
- web/**
- windows/**
- macos/**
- linux/**
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 -14
View File
@@ -1,14 +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
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
-80
View File
@@ -1,80 +0,0 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
namespace "id.ptsemangat.siab_scale"
compileSdk 36
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
applicationId "id.ptsemangat.siab_scale"
minSdkVersion flutter.minSdkVersion
targetSdk 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
signingConfigs {
release {
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
flutter {
source '../..'
}
dependencies {}
+1 -1
View File
@@ -14,7 +14,7 @@ if (keystorePropertiesFile.exists()) {
android {
namespace = "id.ptsemangat.siab_scale"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
ndkVersion = "27.0.12077973"
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
+7
View File
@@ -6,6 +6,12 @@
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
# Play Core deferred components
-dontwarn com.google.android.play.core.**
-dontwarn com.google.android.play.core.splitcompat.**
-dontwarn com.google.android.play.core.splitinstall.**
-dontwarn com.google.android.play.core.tasks.**
# SIAB Scale app
-keep class id.ptsemangat.siab_scale.** { *; }
@@ -14,3 +20,4 @@
# sqflite
-keep class com.tekartik.sqflite.** { *; }
+7 -7
View File
@@ -1,7 +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>
<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>
+37 -37
View File
@@ -1,37 +1,37 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- Storage permissions for saving CSV to Downloads on older Android versions -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
<application
android:label="SIAB Scale"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<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>
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- Storage permissions for saving CSV to Downloads on older Android versions -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
<application
android:label="SIAB Scale"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<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>
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
@@ -1,12 +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>
<?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>
@@ -1,12 +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>
<?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>
@@ -1,18 +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>
<?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>
+18 -18
View File
@@ -1,18 +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>
<?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>
+7 -7
View File
@@ -1,7 +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>
<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>
-31
View File
@@ -1,31 +0,0 @@
buildscript {
ext.kotlin_version = '2.0.0'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
+24 -24
View File
@@ -1,24 +1,24 @@
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)
}
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)
}
+5 -5
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip
+26 -26
View File
@@ -1,26 +1,26 @@
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.9.1" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
}
include(":app")
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 "9.0.0" apply false
id("org.jetbrains.kotlin.android") version "2.2.20" apply false
}
include(":app")
Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 432 432" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-11247.479417,-220.878492)">
<g transform="matrix(3.556675,0,0,1,2063.451047,0)">
<g transform="matrix(0.134003,0,0,0.476604,2271.742994,75.055391)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:rgb(0,214,156);"/>
</g>
<g transform="matrix(0.959532,0,0,0.959532,-7272.887866,171.062992)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538ZM10624.96,701.428L10608.01,602.96C10599.711,554.748 10557.898,519.518 10508.977,519.518L10422.144,519.518C10372.585,519.518 10330.426,555.648 10322.839,604.623L10307.572,703.169C10302.871,733.512 10311.666,764.394 10331.647,787.709C10351.628,811.024 10380.799,824.442 10411.505,824.442L10521.312,824.442C10552.325,824.442 10581.758,810.754 10601.741,787.037C10621.724,763.32 10630.221,731.992 10624.96,701.428ZM10556.997,624.883L10571.236,707.601C10573.924,723.216 10569.583,739.222 10559.373,751.339C10549.163,763.456 10534.126,770.45 10518.281,770.45L10414.485,770.45C10398.797,770.45 10383.893,763.594 10373.685,751.682C10363.476,739.771 10358.983,723.993 10361.385,708.49L10374.179,625.907C10378.85,595.755 10404.806,573.511 10435.317,573.511L10496.026,573.511C10526.145,573.511 10551.887,595.201 10556.997,624.883ZM10518.185,644.084L10485.169,677.1C10481.077,681.192 10474.443,681.192 10470.352,677.1L10460.989,667.737C10456.897,663.646 10456.897,657.012 10460.989,652.92C10470.018,643.891 10485.161,628.748 10494.002,619.902C10495.699,618.205 10496.43,615.769 10495.948,613.418C10495.466,611.068 10493.836,609.116 10491.609,608.224C10483.596,604.979 10474.84,603.193 10465.67,603.193C10427.463,603.193 10396.444,634.212 10396.444,672.419C10396.444,710.626 10427.463,741.645 10465.67,741.645C10503.877,741.645 10534.896,710.626 10534.896,672.419C10534.896,663.249 10533.11,654.493 10529.869,646.479C10528.976,644.25 10527.024,642.619 10524.672,642.137C10522.319,641.655 10519.882,642.386 10518.185,644.084ZM10323.418,417.171L10326.515,437.161C10331.987,472.482 10362.392,498.54 10398.135,498.54L10532.582,498.54C10567.865,498.54 10598.02,473.132 10604.006,438.36L10607.56,417.711C10608.244,413.738 10607.143,409.665 10604.55,406.578C10601.958,403.491 10598.137,401.702 10594.105,401.689L10568.061,401.604C10561.653,401.583 10556.086,406.008 10554.661,412.256L10550.796,429.201C10549.269,438.068 10541.579,444.547 10532.582,444.547L10398.135,444.547C10389.02,444.547 10381.267,437.902 10379.871,428.895L10377.426,413.111C10376.396,406.46 10370.687,401.543 10363.957,401.51L10337.023,401.375C10333.012,401.355 10329.194,403.094 10326.576,406.134C10323.958,409.173 10322.804,413.207 10323.418,417.171Z" style="fill:rgb(6,29,132);"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 432 432" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-11876.484028,-220.878492)">
<g transform="matrix(3.556675,0,0,1,2063.451047,0)">
<g transform="matrix(0.134003,0,0,0.476604,2448.59488,75.055391)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:white;"/>
</g>
<g transform="matrix(0.959532,0,0,0.959532,-7272.887866,171.062992)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538ZM10624.96,701.428L10608.01,602.96C10599.711,554.748 10557.898,519.518 10508.977,519.518L10422.144,519.518C10372.585,519.518 10330.426,555.648 10322.839,604.623L10307.572,703.169C10302.871,733.512 10311.666,764.394 10331.647,787.709C10351.628,811.024 10380.799,824.442 10411.505,824.442L10521.312,824.442C10552.325,824.442 10581.758,810.754 10601.741,787.037C10621.724,763.32 10630.221,731.992 10624.96,701.428ZM10556.997,624.883L10571.236,707.601C10573.924,723.216 10569.583,739.222 10559.373,751.339C10549.163,763.456 10534.126,770.45 10518.281,770.45L10414.485,770.45C10398.797,770.45 10383.893,763.594 10373.685,751.682C10363.476,739.771 10358.983,723.993 10361.385,708.49L10374.179,625.907C10378.85,595.755 10404.806,573.511 10435.317,573.511L10496.026,573.511C10526.145,573.511 10551.887,595.201 10556.997,624.883ZM10518.185,644.084L10485.169,677.1C10481.077,681.192 10474.443,681.192 10470.352,677.1L10460.989,667.737C10456.897,663.646 10456.897,657.012 10460.989,652.92C10470.018,643.891 10485.161,628.748 10494.002,619.902C10495.699,618.205 10496.43,615.769 10495.948,613.418C10495.466,611.068 10493.836,609.116 10491.609,608.224C10483.596,604.979 10474.84,603.193 10465.67,603.193C10427.463,603.193 10396.444,634.212 10396.444,672.419C10396.444,710.626 10427.463,741.645 10465.67,741.645C10503.877,741.645 10534.896,710.626 10534.896,672.419C10534.896,663.249 10533.11,654.493 10529.869,646.479C10528.976,644.25 10527.024,642.619 10524.672,642.137C10522.319,641.655 10519.882,642.386 10518.185,644.084ZM10323.418,417.171L10326.515,437.161C10331.987,472.482 10362.392,498.54 10398.135,498.54L10532.582,498.54C10567.865,498.54 10598.02,473.132 10604.006,438.36L10607.56,417.711C10608.244,413.738 10607.143,409.665 10604.55,406.578C10601.958,403.491 10598.137,401.702 10594.105,401.689L10568.061,401.604C10561.653,401.583 10556.086,406.008 10554.661,412.256L10550.796,429.201C10549.269,438.068 10541.579,444.547 10532.582,444.547L10398.135,444.547C10389.02,444.547 10381.267,437.902 10379.871,428.895L10377.426,413.111C10376.396,406.46 10370.687,401.543 10363.957,401.51L10337.023,401.375C10333.012,401.355 10329.194,403.094 10326.576,406.134C10323.958,409.173 10322.804,413.207 10323.418,417.171Z" style="fill:rgb(6,29,132);"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 432 432" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-10629.023523,-220.878492)">
<g transform="matrix(3.556675,0,0,1,2063.451047,0)">
<g transform="matrix(0.84375,0,0,0.84375,-299.008261,-854.902758)">
<g transform="matrix(0.103708,0,0,0.368856,2971.190037,1118.626194)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:white;"/>
</g>
<g transform="matrix(0.152391,0,0,0.542006,1685.662521,1198.800036)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538ZM10323.418,417.171L10326.515,437.161C10331.987,472.482 10362.392,498.54 10398.135,498.54L10532.582,498.54C10567.865,498.54 10598.02,473.132 10604.006,438.36L10607.56,417.711C10608.244,413.738 10607.143,409.665 10604.55,406.578C10601.958,403.491 10598.137,401.702 10594.105,401.689L10568.061,401.604C10561.653,401.583 10556.086,406.008 10554.661,412.256L10550.796,429.201C10549.269,438.068 10541.579,444.547 10532.582,444.547L10398.135,444.547C10389.02,444.547 10381.267,437.902 10379.871,428.895L10377.426,413.111C10376.396,406.46 10370.687,401.543 10363.957,401.51L10337.023,401.375C10333.012,401.355 10329.194,403.094 10326.576,406.134C10323.958,409.173 10322.804,413.207 10323.418,417.171ZM10624.96,701.428L10608.01,602.96C10599.711,554.748 10557.898,519.518 10508.977,519.518L10422.144,519.518C10372.585,519.518 10330.426,555.648 10322.839,604.623L10307.572,703.169C10302.871,733.512 10311.666,764.394 10331.647,787.709C10351.628,811.024 10380.799,824.442 10411.505,824.442L10521.312,824.442C10552.325,824.442 10581.758,810.754 10601.741,787.037C10621.724,763.32 10630.221,731.992 10624.96,701.428ZM10556.997,624.883L10571.236,707.601C10573.924,723.216 10569.583,739.222 10559.373,751.339C10549.163,763.456 10534.126,770.45 10518.281,770.45L10414.485,770.45C10398.797,770.45 10383.893,763.594 10373.685,751.682C10363.476,739.771 10358.983,723.993 10361.385,708.49L10374.179,625.907C10378.85,595.755 10404.806,573.511 10435.317,573.511L10496.026,573.511C10526.145,573.511 10551.887,595.201 10556.997,624.883ZM10518.185,644.084L10485.169,677.1C10481.077,681.192 10474.443,681.192 10470.352,677.1L10460.989,667.737C10456.897,663.646 10456.897,657.012 10460.989,652.92C10470.018,643.891 10485.161,628.748 10494.002,619.902C10495.699,618.205 10496.43,615.769 10495.948,613.418C10495.466,611.068 10493.836,609.116 10491.609,608.224C10483.596,604.979 10474.84,603.193 10465.67,603.193C10427.463,603.193 10396.444,634.212 10396.444,672.419C10396.444,710.626 10427.463,741.645 10465.67,741.645C10503.877,741.645 10534.896,710.626 10534.896,672.419C10534.896,663.249 10533.11,654.493 10529.869,646.479C10528.976,644.25 10527.024,642.619 10524.672,642.137C10522.319,641.655 10519.882,642.386 10518.185,644.084Z" style="fill:rgb(0,214,156);"/>
</g>
<g transform="matrix(0.281162,0,0,1,-580.163012,0)">
<path d="M13654.154,1424.909C13653.821,1422.761 13654.447,1420.574 13655.866,1418.927C13657.284,1417.279 13659.354,1416.337 13661.528,1416.348L13676.126,1416.42C13679.774,1416.439 13682.868,1419.104 13683.427,1422.708L13684.752,1431.264C13685.508,1436.146 13689.711,1439.747 13694.651,1439.747L13767.522,1439.747C13772.399,1439.747 13776.567,1436.235 13777.394,1431.429L13779.489,1422.245C13780.261,1418.858 13783.278,1416.46 13786.752,1416.471L13800.868,1416.518C13803.053,1416.525 13805.124,1417.494 13806.529,1419.168C13807.935,1420.841 13808.531,1423.048 13808.161,1425.202L13806.234,1436.394C13802.99,1455.24 13786.645,1469.012 13767.522,1469.012L13694.651,1469.012C13675.278,1469.012 13658.798,1454.888 13655.832,1435.744L13654.154,1424.909Z" style="fill:rgb(6,29,132);"/>
</g>
<g transform="matrix(0.281162,0,0,1,-580.163012,0)">
<path d="M13817.591,1578.978C13820.443,1595.544 13815.838,1612.524 13805.007,1625.379C13794.176,1638.233 13778.223,1645.652 13761.414,1645.652L13701.897,1645.652C13685.255,1645.652 13669.444,1638.379 13658.614,1625.743C13647.784,1613.106 13643.018,1596.368 13645.565,1579.921L13653.84,1526.509C13657.953,1499.965 13680.803,1480.382 13707.664,1480.382L13754.728,1480.382C13781.244,1480.382 13803.906,1499.477 13808.405,1525.608L13817.591,1578.978ZM13780.755,1537.49C13777.986,1521.402 13764.033,1509.646 13747.708,1509.646L13714.804,1509.646C13698.267,1509.646 13684.198,1521.703 13681.667,1538.045L13674.732,1582.806C13673.43,1591.208 13675.866,1599.76 13681.399,1606.216C13686.932,1612.672 13695.01,1616.388 13703.513,1616.388L13759.771,1616.388C13768.359,1616.388 13776.509,1612.598 13782.043,1606.03C13787.576,1599.462 13789.929,1590.787 13788.472,1582.324L13780.755,1537.49Z" style="fill:rgb(6,29,132);"/>
</g>
<g transform="matrix(0.281162,0,0,1,-580.163012,0)">
<path d="M13759.719,1547.897C13760.639,1546.977 13761.96,1546.58 13763.234,1546.842C13764.509,1547.103 13765.568,1547.987 13766.052,1549.195C13767.808,1553.539 13768.776,1558.285 13768.776,1563.255C13768.776,1583.963 13751.964,1600.776 13731.255,1600.776C13710.547,1600.776 13693.735,1583.963 13693.735,1563.255C13693.735,1542.546 13710.547,1525.734 13731.255,1525.734C13736.226,1525.734 13740.971,1526.702 13745.314,1528.461C13746.521,1528.944 13747.405,1530.002 13747.666,1531.276C13747.927,1532.55 13747.531,1533.871 13746.611,1534.79C13741.819,1539.585 13733.612,1547.793 13728.718,1552.686C13726.5,1554.904 13726.501,1558.5 13728.718,1560.717L13733.793,1565.792C13736.01,1568.01 13739.606,1568.01 13741.824,1565.792L13759.719,1547.897Z" style="fill:rgb(6,29,132);"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 432 432" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-10052.182314,-215.925716)">
<g transform="matrix(3.556675,0,0,1,2063.451047,0)">
<g transform="matrix(0.134003,0,0,0.476604,1935.671456,70.102616)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:rgb(6,29,132);"/>
</g>
<g transform="matrix(0.646902,0,0,0.646902,822.275361,112.266714)">
<g transform="matrix(1.483273,0,0,1.483273,-12513.742858,90.889027)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538Z" style="fill:white;"/>
</g>
<g transform="matrix(0.837848,0,0,0.837848,563.311523,258.627883)">
<g transform="matrix(0.764685,0,0,0.764685,1814.51336,-94.801291)">
<g transform="matrix(0.843817,0,0,1,973.42738,670.673266)">
<path d="M996.456,815.382C1010.891,886.141 987.579,958.668 932.752,1013.576C877.925,1068.484 797.174,1100.174 712.085,1100.174C614.422,1100.174 508.13,1100.174 410.814,1100.174C326.571,1100.174 246.534,1069.108 191.713,1015.131C136.893,961.155 112.765,889.659 125.662,819.41C139.686,743.025 154.576,661.927 167.549,591.266C188.366,477.884 304.034,394.237 440.005,394.237C516.746,394.237 601.794,394.237 678.242,394.237C812.464,394.237 927.183,475.799 949.952,587.417C964.298,657.739 980.831,738.787 996.456,815.382ZM809.991,638.17C795.972,569.452 725.344,519.237 642.709,519.237C589.643,519.237 529.429,519.237 476.147,519.237C392.435,519.237 321.222,570.735 308.406,640.54C297.616,699.31 284.584,770.291 273.304,831.73C266.715,867.62 279.042,904.148 307.05,931.725C335.058,959.302 375.949,975.174 418.99,975.174C507.403,975.174 614.937,975.174 703.769,975.174C747.242,975.174 788.498,958.983 816.51,930.93C844.521,902.878 856.431,865.823 849.056,829.672C836.451,767.879 821.939,696.744 809.991,638.17Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.843817,0,0,-1,973.42738,1410.581134)">
<path d="M169.137,582.616C167.452,591.793 170.619,601.132 177.801,608.169C184.983,615.205 195.46,619.231 206.465,619.185C230.149,619.085 258.821,618.965 280.361,618.874C298.825,618.797 314.488,607.413 317.315,592.016C320.486,574.745 324.024,555.473 324.024,555.473C327.852,534.621 349.125,519.237 374.132,519.237L743.005,519.237C767.69,519.237 788.789,534.237 792.976,554.765C792.976,554.765 798.715,575.995 803.581,593.996C807.492,608.461 822.764,618.705 840.347,618.656C860.96,618.6 888.653,618.523 911.802,618.459C922.863,618.429 933.347,614.288 940.46,607.14C947.573,599.993 950.594,590.564 948.718,581.365C944.059,558.529 938.966,533.56 938.966,533.56C922.544,453.06 839.808,394.237 743.005,394.237L374.132,394.237C276.068,394.237 192.647,454.564 177.634,536.336C177.634,536.336 173.216,560.398 169.137,582.616Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.923041,-0,0,0.923041,854.504081,621.345248)">
<path d="M771.961,792.978C776.219,788.719 782.332,786.884 788.231,788.093C794.131,789.302 799.029,793.394 801.268,798.984C809.395,819.084 813.877,841.045 813.877,864.045C813.877,959.873 736.076,1037.674 640.248,1037.674C544.419,1037.674 466.619,959.873 466.619,864.045C466.619,768.216 544.419,690.416 640.248,690.416C663.247,690.416 685.208,694.897 705.305,703.034C710.892,705.272 714.981,710.167 716.189,716.063C717.398,721.96 715.564,728.068 711.308,732.324C689.133,754.513 651.152,792.493 628.507,815.139C618.244,825.402 618.244,842.041 628.507,852.303C635.961,859.758 644.535,868.331 651.989,875.786C662.252,886.048 678.891,886.048 689.153,875.786C711.799,853.14 749.779,815.16 771.961,792.978Z" style="fill:rgb(0,214,156);"/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 432 432" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-13047.92582,-215.925716)">
<g transform="matrix(3.556675,0,0,1,2063.451047,0)">
<g transform="matrix(0.134003,0,0,0.476604,2777.959223,70.102616)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:none;"/>
</g>
<g transform="matrix(0.646902,0,0,0.646902,822.275361,112.266714)">
<g transform="matrix(1.483273,0,0,1.483273,-12513.742858,90.889027)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538Z" style="fill:white;"/>
</g>
<g transform="matrix(0.837848,0,0,0.837848,563.311523,258.627883)">
<g transform="matrix(0.764685,0,0,0.764685,1814.51336,-94.801291)">
<g transform="matrix(0.843817,0,0,1,973.42738,670.673266)">
<path d="M996.456,815.382C1010.891,886.141 987.579,958.668 932.752,1013.576C877.925,1068.484 797.174,1100.174 712.085,1100.174C614.422,1100.174 508.13,1100.174 410.814,1100.174C326.571,1100.174 246.534,1069.108 191.713,1015.131C136.893,961.155 112.765,889.659 125.662,819.41C139.686,743.025 154.576,661.927 167.549,591.266C188.366,477.884 304.034,394.237 440.005,394.237C516.746,394.237 601.794,394.237 678.242,394.237C812.464,394.237 927.183,475.799 949.952,587.417C964.298,657.739 980.831,738.787 996.456,815.382ZM809.991,638.17C795.972,569.452 725.344,519.237 642.709,519.237C589.643,519.237 529.429,519.237 476.147,519.237C392.435,519.237 321.222,570.735 308.406,640.54C297.616,699.31 284.584,770.291 273.304,831.73C266.715,867.62 279.042,904.148 307.05,931.725C335.058,959.302 375.949,975.174 418.99,975.174C507.403,975.174 614.937,975.174 703.769,975.174C747.242,975.174 788.498,958.983 816.51,930.93C844.521,902.878 856.431,865.823 849.056,829.672C836.451,767.879 821.939,696.744 809.991,638.17Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.843817,0,0,-1,973.42738,1410.581134)">
<path d="M169.137,582.616C167.452,591.793 170.619,601.132 177.801,608.169C184.983,615.205 195.46,619.231 206.465,619.185C230.149,619.085 258.821,618.965 280.361,618.874C298.825,618.797 314.488,607.413 317.315,592.016C320.486,574.745 324.024,555.473 324.024,555.473C327.852,534.621 349.125,519.237 374.132,519.237L743.005,519.237C767.69,519.237 788.789,534.237 792.976,554.765C792.976,554.765 798.715,575.995 803.581,593.996C807.492,608.461 822.764,618.705 840.347,618.656C860.96,618.6 888.653,618.523 911.802,618.459C922.863,618.429 933.347,614.288 940.46,607.14C947.573,599.993 950.594,590.564 948.718,581.365C944.059,558.529 938.966,533.56 938.966,533.56C922.544,453.06 839.808,394.237 743.005,394.237L374.132,394.237C276.068,394.237 192.647,454.564 177.634,536.336C177.634,536.336 173.216,560.398 169.137,582.616Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.923041,-0,0,0.923041,854.504081,621.345248)">
<path d="M771.961,792.978C776.219,788.719 782.332,786.884 788.231,788.093C794.131,789.302 799.029,793.394 801.268,798.984C809.395,819.084 813.877,841.045 813.877,864.045C813.877,959.873 736.076,1037.674 640.248,1037.674C544.419,1037.674 466.619,959.873 466.619,864.045C466.619,768.216 544.419,690.416 640.248,690.416C663.247,690.416 685.208,694.897 705.305,703.034C710.892,705.272 714.981,710.167 716.189,716.063C717.398,721.96 715.564,728.068 711.308,732.324C689.133,754.513 651.152,792.493 628.507,815.139C618.244,825.402 618.244,842.041 628.507,852.303C635.961,859.758 644.535,868.331 651.989,875.786C662.252,886.048 678.891,886.048 689.153,875.786C711.799,853.14 749.779,815.16 771.961,792.978Z" style="fill:rgb(0,214,156);"/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 432 432" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-12479.308577,-215.925716)">
<g transform="matrix(3.556675,0,0,1,2063.451047,0)">
<g transform="matrix(0.134003,0,0,0.476604,2618.08594,70.102616)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:white;"/>
</g>
<g transform="matrix(0.646902,0,0,0.646902,822.275361,112.266714)">
<g transform="matrix(1.483273,0,0,1.483273,-12513.742858,90.889027)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538Z" style="fill:white;"/>
</g>
<g transform="matrix(0.837848,0,0,0.837848,563.311523,258.627883)">
<g transform="matrix(0.764685,0,0,0.764685,1814.51336,-94.801291)">
<g transform="matrix(0.843817,0,0,1,973.42738,670.673266)">
<path d="M996.456,815.382C1010.891,886.141 987.579,958.668 932.752,1013.576C877.925,1068.484 797.174,1100.174 712.085,1100.174C614.422,1100.174 508.13,1100.174 410.814,1100.174C326.571,1100.174 246.534,1069.108 191.713,1015.131C136.893,961.155 112.765,889.659 125.662,819.41C139.686,743.025 154.576,661.927 167.549,591.266C188.366,477.884 304.034,394.237 440.005,394.237C516.746,394.237 601.794,394.237 678.242,394.237C812.464,394.237 927.183,475.799 949.952,587.417C964.298,657.739 980.831,738.787 996.456,815.382ZM809.991,638.17C795.972,569.452 725.344,519.237 642.709,519.237C589.643,519.237 529.429,519.237 476.147,519.237C392.435,519.237 321.222,570.735 308.406,640.54C297.616,699.31 284.584,770.291 273.304,831.73C266.715,867.62 279.042,904.148 307.05,931.725C335.058,959.302 375.949,975.174 418.99,975.174C507.403,975.174 614.937,975.174 703.769,975.174C747.242,975.174 788.498,958.983 816.51,930.93C844.521,902.878 856.431,865.823 849.056,829.672C836.451,767.879 821.939,696.744 809.991,638.17Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.843817,0,0,-1,973.42738,1410.581134)">
<path d="M169.137,582.616C167.452,591.793 170.619,601.132 177.801,608.169C184.983,615.205 195.46,619.231 206.465,619.185C230.149,619.085 258.821,618.965 280.361,618.874C298.825,618.797 314.488,607.413 317.315,592.016C320.486,574.745 324.024,555.473 324.024,555.473C327.852,534.621 349.125,519.237 374.132,519.237L743.005,519.237C767.69,519.237 788.789,534.237 792.976,554.765C792.976,554.765 798.715,575.995 803.581,593.996C807.492,608.461 822.764,618.705 840.347,618.656C860.96,618.6 888.653,618.523 911.802,618.459C922.863,618.429 933.347,614.288 940.46,607.14C947.573,599.993 950.594,590.564 948.718,581.365C944.059,558.529 938.966,533.56 938.966,533.56C922.544,453.06 839.808,394.237 743.005,394.237L374.132,394.237C276.068,394.237 192.647,454.564 177.634,536.336C177.634,536.336 173.216,560.398 169.137,582.616Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.923041,-0,0,0.923041,854.504081,621.345248)">
<path d="M771.961,792.978C776.219,788.719 782.332,786.884 788.231,788.093C794.131,789.302 799.029,793.394 801.268,798.984C809.395,819.084 813.877,841.045 813.877,864.045C813.877,959.873 736.076,1037.674 640.248,1037.674C544.419,1037.674 466.619,959.873 466.619,864.045C466.619,768.216 544.419,690.416 640.248,690.416C663.247,690.416 685.208,694.897 705.305,703.034C710.892,705.272 714.981,710.167 716.189,716.063C717.398,721.96 715.564,728.068 711.308,732.324C689.133,754.513 651.152,792.493 628.507,815.139C618.244,825.402 618.244,842.041 628.507,852.303C635.961,859.758 644.535,868.331 651.989,875.786C662.252,886.048 678.891,886.048 689.153,875.786C711.799,853.14 749.779,815.16 771.961,792.978Z" style="fill:rgb(0,214,156);"/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-11169.931337,726.774609)">
<g transform="matrix(0.564865,0,0,0.564865,9861.276207,-899.601987)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:rgb(6,29,132);"/>
</g>
<g transform="matrix(0.646902,0,0,0.646902,822.275361,112.266714)">
<g transform="matrix(1.483273,0,0,1.483273,-12513.742858,90.889027)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538Z" style="fill:white;"/>
</g>
<g transform="matrix(0.837848,0,0,0.837848,563.311523,258.627883)">
<g transform="matrix(0.764685,0,0,0.764685,1814.51336,-94.801291)">
<g transform="matrix(0.843817,0,0,1,973.42738,670.673266)">
<path d="M996.456,815.382C1010.891,886.141 987.579,958.668 932.752,1013.576C877.925,1068.484 797.174,1100.174 712.085,1100.174C614.422,1100.174 508.13,1100.174 410.814,1100.174C326.571,1100.174 246.534,1069.108 191.713,1015.131C136.893,961.155 112.765,889.659 125.662,819.41C139.686,743.025 154.576,661.927 167.549,591.266C188.366,477.884 304.034,394.237 440.005,394.237C516.746,394.237 601.794,394.237 678.242,394.237C812.464,394.237 927.183,475.799 949.952,587.417C964.298,657.739 980.831,738.787 996.456,815.382ZM809.991,638.17C795.972,569.452 725.344,519.237 642.709,519.237C589.643,519.237 529.429,519.237 476.147,519.237C392.435,519.237 321.222,570.735 308.406,640.54C297.616,699.31 284.584,770.291 273.304,831.73C266.715,867.62 279.042,904.148 307.05,931.725C335.058,959.302 375.949,975.174 418.99,975.174C507.403,975.174 614.937,975.174 703.769,975.174C747.242,975.174 788.498,958.983 816.51,930.93C844.521,902.878 856.431,865.823 849.056,829.672C836.451,767.879 821.939,696.744 809.991,638.17Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.843817,0,0,-1,973.42738,1410.581134)">
<path d="M169.137,582.616C167.452,591.793 170.619,601.132 177.801,608.169C184.983,615.205 195.46,619.231 206.465,619.185C230.149,619.085 258.821,618.965 280.361,618.874C298.825,618.797 314.488,607.413 317.315,592.016C320.486,574.745 324.024,555.473 324.024,555.473C327.852,534.621 349.125,519.237 374.132,519.237L743.005,519.237C767.69,519.237 788.789,534.237 792.976,554.765C792.976,554.765 798.715,575.995 803.581,593.996C807.492,608.461 822.764,618.705 840.347,618.656C860.96,618.6 888.653,618.523 911.802,618.459C922.863,618.429 933.347,614.288 940.46,607.14C947.573,599.993 950.594,590.564 948.718,581.365C944.059,558.529 938.966,533.56 938.966,533.56C922.544,453.06 839.808,394.237 743.005,394.237L374.132,394.237C276.068,394.237 192.647,454.564 177.634,536.336C177.634,536.336 173.216,560.398 169.137,582.616Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.923041,-0,0,0.923041,854.504081,621.345248)">
<path d="M771.961,792.978C776.219,788.719 782.332,786.884 788.231,788.093C794.131,789.302 799.029,793.394 801.268,798.984C809.395,819.084 813.877,841.045 813.877,864.045C813.877,959.873 736.076,1037.674 640.248,1037.674C544.419,1037.674 466.619,959.873 466.619,864.045C466.619,768.216 544.419,690.416 640.248,690.416C663.247,690.416 685.208,694.897 705.305,703.034C710.892,705.272 714.981,710.167 716.189,716.063C717.398,721.96 715.564,728.068 711.308,732.324C689.133,754.513 651.152,792.493 628.507,815.139C618.244,825.402 618.244,842.041 628.507,852.303C635.961,859.758 644.535,868.331 651.989,875.786C662.252,886.048 678.891,886.048 689.153,875.786C711.799,853.14 749.779,815.16 771.961,792.978Z" style="fill:rgb(0,214,156);"/>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-9924.644661,726.774609)">
<g transform="matrix(0.564865,0,0,0.564865,8615.989531,-899.601987)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:none;"/>
</g>
<g transform="matrix(0.646902,0,0,0.646902,822.275361,112.266714)">
<g transform="matrix(1.483273,0,0,1.483273,-12513.742858,90.889027)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538Z" style="fill:white;"/>
</g>
<g transform="matrix(0.837848,0,0,0.837848,563.311523,258.627883)">
<g transform="matrix(0.764685,0,0,0.764685,1814.51336,-94.801291)">
<g transform="matrix(0.843817,0,0,1,973.42738,670.673266)">
<path d="M996.456,815.382C1010.891,886.141 987.579,958.668 932.752,1013.576C877.925,1068.484 797.174,1100.174 712.085,1100.174C614.422,1100.174 508.13,1100.174 410.814,1100.174C326.571,1100.174 246.534,1069.108 191.713,1015.131C136.893,961.155 112.765,889.659 125.662,819.41C139.686,743.025 154.576,661.927 167.549,591.266C188.366,477.884 304.034,394.237 440.005,394.237C516.746,394.237 601.794,394.237 678.242,394.237C812.464,394.237 927.183,475.799 949.952,587.417C964.298,657.739 980.831,738.787 996.456,815.382ZM809.991,638.17C795.972,569.452 725.344,519.237 642.709,519.237C589.643,519.237 529.429,519.237 476.147,519.237C392.435,519.237 321.222,570.735 308.406,640.54C297.616,699.31 284.584,770.291 273.304,831.73C266.715,867.62 279.042,904.148 307.05,931.725C335.058,959.302 375.949,975.174 418.99,975.174C507.403,975.174 614.937,975.174 703.769,975.174C747.242,975.174 788.498,958.983 816.51,930.93C844.521,902.878 856.431,865.823 849.056,829.672C836.451,767.879 821.939,696.744 809.991,638.17Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.843817,0,0,-1,973.42738,1410.581134)">
<path d="M169.137,582.616C167.452,591.793 170.619,601.132 177.801,608.169C184.983,615.205 195.46,619.231 206.465,619.185C230.149,619.085 258.821,618.965 280.361,618.874C298.825,618.797 314.488,607.413 317.315,592.016C320.486,574.745 324.024,555.473 324.024,555.473C327.852,534.621 349.125,519.237 374.132,519.237L743.005,519.237C767.69,519.237 788.789,534.237 792.976,554.765C792.976,554.765 798.715,575.995 803.581,593.996C807.492,608.461 822.764,618.705 840.347,618.656C860.96,618.6 888.653,618.523 911.802,618.459C922.863,618.429 933.347,614.288 940.46,607.14C947.573,599.993 950.594,590.564 948.718,581.365C944.059,558.529 938.966,533.56 938.966,533.56C922.544,453.06 839.808,394.237 743.005,394.237L374.132,394.237C276.068,394.237 192.647,454.564 177.634,536.336C177.634,536.336 173.216,560.398 169.137,582.616Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.923041,-0,0,0.923041,854.504081,621.345248)">
<path d="M771.961,792.978C776.219,788.719 782.332,786.884 788.231,788.093C794.131,789.302 799.029,793.394 801.268,798.984C809.395,819.084 813.877,841.045 813.877,864.045C813.877,959.873 736.076,1037.674 640.248,1037.674C544.419,1037.674 466.619,959.873 466.619,864.045C466.619,768.216 544.419,690.416 640.248,690.416C663.247,690.416 685.208,694.897 705.305,703.034C710.892,705.272 714.981,710.167 716.189,716.063C717.398,721.96 715.564,728.068 711.308,732.324C689.133,754.513 651.152,792.493 628.507,815.139C618.244,825.402 618.244,842.041 628.507,852.303C635.961,859.758 644.535,868.331 651.989,875.786C662.252,886.048 678.891,886.048 689.153,875.786C711.799,853.14 749.779,815.16 771.961,792.978Z" style="fill:rgb(0,214,156);"/>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-10529.681152,726.774609)">
<g transform="matrix(0.564865,0,0,0.564865,9221.026021,-899.601987)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:white;"/>
</g>
<g transform="matrix(0.646902,0,0,0.646902,822.275361,112.266714)">
<g transform="matrix(1.483273,0,0,1.483273,-12513.742858,90.889027)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538Z" style="fill:white;"/>
</g>
<g transform="matrix(0.837848,0,0,0.837848,563.311523,258.627883)">
<g transform="matrix(0.764685,0,0,0.764685,1814.51336,-94.801291)">
<g transform="matrix(0.843817,0,0,1,973.42738,670.673266)">
<path d="M996.456,815.382C1010.891,886.141 987.579,958.668 932.752,1013.576C877.925,1068.484 797.174,1100.174 712.085,1100.174C614.422,1100.174 508.13,1100.174 410.814,1100.174C326.571,1100.174 246.534,1069.108 191.713,1015.131C136.893,961.155 112.765,889.659 125.662,819.41C139.686,743.025 154.576,661.927 167.549,591.266C188.366,477.884 304.034,394.237 440.005,394.237C516.746,394.237 601.794,394.237 678.242,394.237C812.464,394.237 927.183,475.799 949.952,587.417C964.298,657.739 980.831,738.787 996.456,815.382ZM809.991,638.17C795.972,569.452 725.344,519.237 642.709,519.237C589.643,519.237 529.429,519.237 476.147,519.237C392.435,519.237 321.222,570.735 308.406,640.54C297.616,699.31 284.584,770.291 273.304,831.73C266.715,867.62 279.042,904.148 307.05,931.725C335.058,959.302 375.949,975.174 418.99,975.174C507.403,975.174 614.937,975.174 703.769,975.174C747.242,975.174 788.498,958.983 816.51,930.93C844.521,902.878 856.431,865.823 849.056,829.672C836.451,767.879 821.939,696.744 809.991,638.17Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.843817,0,0,-1,973.42738,1410.581134)">
<path d="M169.137,582.616C167.452,591.793 170.619,601.132 177.801,608.169C184.983,615.205 195.46,619.231 206.465,619.185C230.149,619.085 258.821,618.965 280.361,618.874C298.825,618.797 314.488,607.413 317.315,592.016C320.486,574.745 324.024,555.473 324.024,555.473C327.852,534.621 349.125,519.237 374.132,519.237L743.005,519.237C767.69,519.237 788.789,534.237 792.976,554.765C792.976,554.765 798.715,575.995 803.581,593.996C807.492,608.461 822.764,618.705 840.347,618.656C860.96,618.6 888.653,618.523 911.802,618.459C922.863,618.429 933.347,614.288 940.46,607.14C947.573,599.993 950.594,590.564 948.718,581.365C944.059,558.529 938.966,533.56 938.966,533.56C922.544,453.06 839.808,394.237 743.005,394.237L374.132,394.237C276.068,394.237 192.647,454.564 177.634,536.336C177.634,536.336 173.216,560.398 169.137,582.616Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.923041,-0,0,0.923041,854.504081,621.345248)">
<path d="M771.961,792.978C776.219,788.719 782.332,786.884 788.231,788.093C794.131,789.302 799.029,793.394 801.268,798.984C809.395,819.084 813.877,841.045 813.877,864.045C813.877,959.873 736.076,1037.674 640.248,1037.674C544.419,1037.674 466.619,959.873 466.619,864.045C466.619,768.216 544.419,690.416 640.248,690.416C663.247,690.416 685.208,694.897 705.305,703.034C710.892,705.272 714.981,710.167 716.189,716.063C717.398,721.96 715.564,728.068 711.308,732.324C689.133,754.513 651.152,792.493 628.507,815.139C618.244,825.402 618.244,842.041 628.507,852.303C635.961,859.758 644.535,868.331 651.989,875.786C662.252,886.048 678.891,886.048 689.153,875.786C711.799,853.14 749.779,815.16 771.961,792.978Z" style="fill:rgb(0,214,156);"/>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-16148.147117,726.774609)">
<g transform="matrix(0.564865,0,0,0.564865,14839.491987,-899.601987)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:rgb(0,214,156);"/>
</g>
<g transform="matrix(0.959532,0,0,0.959532,-7272.887866,171.062992)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538ZM10624.96,701.428L10608.01,602.96C10599.711,554.748 10557.898,519.518 10508.977,519.518L10422.144,519.518C10372.585,519.518 10330.426,555.648 10322.839,604.623L10307.572,703.169C10302.871,733.512 10311.666,764.394 10331.647,787.709C10351.628,811.024 10380.799,824.442 10411.505,824.442L10521.312,824.442C10552.325,824.442 10581.758,810.754 10601.741,787.037C10621.724,763.32 10630.221,731.992 10624.96,701.428ZM10556.997,624.883L10571.236,707.601C10573.924,723.216 10569.583,739.222 10559.373,751.339C10549.163,763.456 10534.126,770.45 10518.281,770.45L10414.485,770.45C10398.797,770.45 10383.893,763.594 10373.685,751.682C10363.476,739.771 10358.983,723.993 10361.385,708.49L10374.179,625.907C10378.85,595.755 10404.806,573.511 10435.317,573.511L10496.026,573.511C10526.145,573.511 10551.887,595.201 10556.997,624.883ZM10518.185,644.084L10485.169,677.1C10481.077,681.192 10474.443,681.192 10470.352,677.1L10460.989,667.737C10456.897,663.646 10456.897,657.012 10460.989,652.92C10470.018,643.891 10485.161,628.748 10494.002,619.902C10495.699,618.205 10496.43,615.769 10495.948,613.418C10495.466,611.068 10493.836,609.116 10491.609,608.224C10483.596,604.979 10474.84,603.193 10465.67,603.193C10427.463,603.193 10396.444,634.212 10396.444,672.419C10396.444,710.626 10427.463,741.645 10465.67,741.645C10503.877,741.645 10534.896,710.626 10534.896,672.419C10534.896,663.249 10533.11,654.493 10529.869,646.479C10528.976,644.25 10527.024,642.619 10524.672,642.137C10522.319,641.655 10519.882,642.386 10518.185,644.084ZM10323.418,417.171L10326.515,437.161C10331.987,472.482 10362.392,498.54 10398.135,498.54L10532.582,498.54C10567.865,498.54 10598.02,473.132 10604.006,438.36L10607.56,417.711C10608.244,413.738 10607.143,409.665 10604.55,406.578C10601.958,403.491 10598.137,401.702 10594.105,401.689L10568.061,401.604C10561.653,401.583 10556.086,406.008 10554.661,412.256L10550.796,429.201C10549.269,438.068 10541.579,444.547 10532.582,444.547L10398.135,444.547C10389.02,444.547 10381.267,437.902 10379.871,428.895L10377.426,413.111C10376.396,406.46 10370.687,401.543 10363.957,401.51L10337.023,401.375C10333.012,401.355 10329.194,403.094 10326.576,406.134C10323.958,409.173 10322.804,413.207 10323.418,417.171Z" style="fill:rgb(6,29,132);"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-14943.31376,726.774609)">
<g transform="matrix(0.564865,0,0,0.564865,13634.65863,-899.601987)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:none;"/>
</g>
<g transform="matrix(0.959532,0,0,0.959532,-7272.887866,171.062992)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538ZM10624.96,701.428L10608.01,602.96C10599.711,554.748 10557.898,519.518 10508.977,519.518L10422.144,519.518C10372.585,519.518 10330.426,555.648 10322.839,604.623L10307.572,703.169C10302.871,733.512 10311.666,764.394 10331.647,787.709C10351.628,811.024 10380.799,824.442 10411.505,824.442L10521.312,824.442C10552.325,824.442 10581.758,810.754 10601.741,787.037C10621.724,763.32 10630.221,731.992 10624.96,701.428ZM10556.997,624.883L10571.236,707.601C10573.924,723.216 10569.583,739.222 10559.373,751.339C10549.163,763.456 10534.126,770.45 10518.281,770.45L10414.485,770.45C10398.797,770.45 10383.893,763.594 10373.685,751.682C10363.476,739.771 10358.983,723.993 10361.385,708.49L10374.179,625.907C10378.85,595.755 10404.806,573.511 10435.317,573.511L10496.026,573.511C10526.145,573.511 10551.887,595.201 10556.997,624.883ZM10518.185,644.084L10485.169,677.1C10481.077,681.192 10474.443,681.192 10470.352,677.1L10460.989,667.737C10456.897,663.646 10456.897,657.012 10460.989,652.92C10470.018,643.891 10485.161,628.748 10494.002,619.902C10495.699,618.205 10496.43,615.769 10495.948,613.418C10495.466,611.068 10493.836,609.116 10491.609,608.224C10483.596,604.979 10474.84,603.193 10465.67,603.193C10427.463,603.193 10396.444,634.212 10396.444,672.419C10396.444,710.626 10427.463,741.645 10465.67,741.645C10503.877,741.645 10534.896,710.626 10534.896,672.419C10534.896,663.249 10533.11,654.493 10529.869,646.479C10528.976,644.25 10527.024,642.619 10524.672,642.137C10522.319,641.655 10519.882,642.386 10518.185,644.084ZM10323.418,417.171L10326.515,437.161C10331.987,472.482 10362.392,498.54 10398.135,498.54L10532.582,498.54C10567.865,498.54 10598.02,473.132 10604.006,438.36L10607.56,417.711C10608.244,413.738 10607.143,409.665 10604.55,406.578C10601.958,403.491 10598.137,401.702 10594.105,401.689L10568.061,401.604C10561.653,401.583 10556.086,406.008 10554.661,412.256L10550.796,429.201C10549.269,438.068 10541.579,444.547 10532.582,444.547L10398.135,444.547C10389.02,444.547 10381.267,437.902 10379.871,428.895L10377.426,413.111C10376.396,406.46 10370.687,401.543 10363.957,401.51L10337.023,401.375C10333.012,401.355 10329.194,403.094 10326.576,406.134C10323.958,409.173 10322.804,413.207 10323.418,417.171Z" style="fill:rgb(6,29,132);"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-15515.751862,726.774609)">
<g transform="matrix(0.564865,0,0,0.564865,14207.096732,-899.601987)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:white;"/>
</g>
<g transform="matrix(0.959532,0,0,0.959532,-7272.887866,171.062992)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538ZM10624.96,701.428L10608.01,602.96C10599.711,554.748 10557.898,519.518 10508.977,519.518L10422.144,519.518C10372.585,519.518 10330.426,555.648 10322.839,604.623L10307.572,703.169C10302.871,733.512 10311.666,764.394 10331.647,787.709C10351.628,811.024 10380.799,824.442 10411.505,824.442L10521.312,824.442C10552.325,824.442 10581.758,810.754 10601.741,787.037C10621.724,763.32 10630.221,731.992 10624.96,701.428ZM10556.997,624.883L10571.236,707.601C10573.924,723.216 10569.583,739.222 10559.373,751.339C10549.163,763.456 10534.126,770.45 10518.281,770.45L10414.485,770.45C10398.797,770.45 10383.893,763.594 10373.685,751.682C10363.476,739.771 10358.983,723.993 10361.385,708.49L10374.179,625.907C10378.85,595.755 10404.806,573.511 10435.317,573.511L10496.026,573.511C10526.145,573.511 10551.887,595.201 10556.997,624.883ZM10518.185,644.084L10485.169,677.1C10481.077,681.192 10474.443,681.192 10470.352,677.1L10460.989,667.737C10456.897,663.646 10456.897,657.012 10460.989,652.92C10470.018,643.891 10485.161,628.748 10494.002,619.902C10495.699,618.205 10496.43,615.769 10495.948,613.418C10495.466,611.068 10493.836,609.116 10491.609,608.224C10483.596,604.979 10474.84,603.193 10465.67,603.193C10427.463,603.193 10396.444,634.212 10396.444,672.419C10396.444,710.626 10427.463,741.645 10465.67,741.645C10503.877,741.645 10534.896,710.626 10534.896,672.419C10534.896,663.249 10533.11,654.493 10529.869,646.479C10528.976,644.25 10527.024,642.619 10524.672,642.137C10522.319,641.655 10519.882,642.386 10518.185,644.084ZM10323.418,417.171L10326.515,437.161C10331.987,472.482 10362.392,498.54 10398.135,498.54L10532.582,498.54C10567.865,498.54 10598.02,473.132 10604.006,438.36L10607.56,417.711C10608.244,413.738 10607.143,409.665 10604.55,406.578C10601.958,403.491 10598.137,401.702 10594.105,401.689L10568.061,401.604C10561.653,401.583 10556.086,406.008 10554.661,412.256L10550.796,429.201C10549.269,438.068 10541.579,444.547 10532.582,444.547L10398.135,444.547C10389.02,444.547 10381.267,437.902 10379.871,428.895L10377.426,413.111C10376.396,406.46 10370.687,401.543 10363.957,401.51L10337.023,401.375C10333.012,401.355 10329.194,403.094 10326.576,406.134C10323.958,409.173 10322.804,413.207 10323.418,417.171Z" style="fill:rgb(6,29,132);"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-14156.761195,726.774609)">
<g transform="matrix(0.564865,0,0,0.564865,12848.106064,-899.601987)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:rgb(6,29,132);"/>
</g>
<g transform="matrix(0.959532,0,0,0.959532,-7272.887866,171.062992)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538ZM10323.418,417.171L10326.515,437.161C10331.987,472.482 10362.392,498.54 10398.135,498.54L10532.582,498.54C10567.865,498.54 10598.02,473.132 10604.006,438.36L10607.56,417.711C10608.244,413.738 10607.143,409.665 10604.55,406.578C10601.958,403.491 10598.137,401.702 10594.105,401.689L10568.061,401.604C10561.653,401.583 10556.086,406.008 10554.661,412.256L10550.796,429.201C10549.269,438.068 10541.579,444.547 10532.582,444.547L10398.135,444.547C10389.02,444.547 10381.267,437.902 10379.871,428.895L10377.426,413.111C10376.396,406.46 10370.687,401.543 10363.957,401.51L10337.023,401.375C10333.012,401.355 10329.194,403.094 10326.576,406.134C10323.958,409.173 10322.804,413.207 10323.418,417.171ZM10624.96,701.428L10608.01,602.96C10599.711,554.748 10557.898,519.518 10508.977,519.518L10422.144,519.518C10372.585,519.518 10330.426,555.648 10322.839,604.623L10307.572,703.169C10302.871,733.512 10311.666,764.394 10331.647,787.709C10351.628,811.024 10380.799,824.442 10411.505,824.442L10521.312,824.442C10552.325,824.442 10581.758,810.754 10601.741,787.037C10621.724,763.32 10630.221,731.992 10624.96,701.428ZM10556.997,624.883L10571.236,707.601C10573.924,723.216 10569.583,739.222 10559.373,751.339C10549.163,763.456 10534.126,770.45 10518.281,770.45L10414.485,770.45C10398.797,770.45 10383.893,763.594 10373.685,751.682C10363.476,739.771 10358.983,723.993 10361.385,708.49L10374.179,625.907C10378.85,595.755 10404.806,573.511 10435.317,573.511L10496.026,573.511C10526.145,573.511 10551.887,595.201 10556.997,624.883ZM10518.185,644.084L10485.169,677.1C10481.077,681.192 10474.443,681.192 10470.352,677.1L10460.989,667.737C10456.897,663.646 10456.897,657.012 10460.989,652.92C10470.018,643.891 10485.161,628.748 10494.002,619.902C10495.699,618.205 10496.43,615.769 10495.948,613.418C10495.466,611.068 10493.836,609.116 10491.609,608.224C10483.596,604.979 10474.84,603.193 10465.67,603.193C10427.463,603.193 10396.444,634.212 10396.444,672.419C10396.444,710.626 10427.463,741.645 10465.67,741.645C10503.877,741.645 10534.896,710.626 10534.896,672.419C10534.896,663.249 10533.11,654.493 10529.869,646.479C10528.976,644.25 10527.024,642.619 10524.672,642.137C10522.319,641.655 10519.882,642.386 10518.185,644.084Z" style="fill:rgb(0,214,156);"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-13013.456547,726.774609)">
<g transform="matrix(0.564865,0,0,0.564865,11704.801417,-899.601987)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:none;"/>
</g>
<g transform="matrix(0.959532,0,0,0.959532,-7272.887866,171.062992)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538ZM10323.418,417.171L10326.515,437.161C10331.987,472.482 10362.392,498.54 10398.135,498.54L10532.582,498.54C10567.865,498.54 10598.02,473.132 10604.006,438.36L10607.56,417.711C10608.244,413.738 10607.143,409.665 10604.55,406.578C10601.958,403.491 10598.137,401.702 10594.105,401.689L10568.061,401.604C10561.653,401.583 10556.086,406.008 10554.661,412.256L10550.796,429.201C10549.269,438.068 10541.579,444.547 10532.582,444.547L10398.135,444.547C10389.02,444.547 10381.267,437.902 10379.871,428.895L10377.426,413.111C10376.396,406.46 10370.687,401.543 10363.957,401.51L10337.023,401.375C10333.012,401.355 10329.194,403.094 10326.576,406.134C10323.958,409.173 10322.804,413.207 10323.418,417.171ZM10624.96,701.428L10608.01,602.96C10599.711,554.748 10557.898,519.518 10508.977,519.518L10422.144,519.518C10372.585,519.518 10330.426,555.648 10322.839,604.623L10307.572,703.169C10302.871,733.512 10311.666,764.394 10331.647,787.709C10351.628,811.024 10380.799,824.442 10411.505,824.442L10521.312,824.442C10552.325,824.442 10581.758,810.754 10601.741,787.037C10621.724,763.32 10630.221,731.992 10624.96,701.428ZM10556.997,624.883L10571.236,707.601C10573.924,723.216 10569.583,739.222 10559.373,751.339C10549.163,763.456 10534.126,770.45 10518.281,770.45L10414.485,770.45C10398.797,770.45 10383.893,763.594 10373.685,751.682C10363.476,739.771 10358.983,723.993 10361.385,708.49L10374.179,625.907C10378.85,595.755 10404.806,573.511 10435.317,573.511L10496.026,573.511C10526.145,573.511 10551.887,595.201 10556.997,624.883ZM10518.185,644.084L10485.169,677.1C10481.077,681.192 10474.443,681.192 10470.352,677.1L10460.989,667.737C10456.897,663.646 10456.897,657.012 10460.989,652.92C10470.018,643.891 10485.161,628.748 10494.002,619.902C10495.699,618.205 10496.43,615.769 10495.948,613.418C10495.466,611.068 10493.836,609.116 10491.609,608.224C10483.596,604.979 10474.84,603.193 10465.67,603.193C10427.463,603.193 10396.444,634.212 10396.444,672.419C10396.444,710.626 10427.463,741.645 10465.67,741.645C10503.877,741.645 10534.896,710.626 10534.896,672.419C10534.896,663.249 10533.11,654.493 10529.869,646.479C10528.976,644.25 10527.024,642.619 10524.672,642.137C10522.319,641.655 10519.882,642.386 10518.185,644.084Z" style="fill:rgb(0,214,156);"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-13532.302289,726.774609)">
<g transform="matrix(0.564865,0,0,0.564865,12223.647158,-899.601987)">
<g transform="matrix(0.652999,0,0,0.652999,821.447853,29.128352)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:white;"/>
</g>
<g transform="matrix(0.959532,0,0,0.959532,-7272.887866,171.062992)">
<path d="M10755.151,468.538L10755.151,757.28C10755.151,836.961 10690.46,901.651 10610.78,901.651L10322.037,901.651C10242.357,901.651 10177.666,836.961 10177.666,757.28L10177.666,468.538C10177.666,388.857 10242.357,324.166 10322.037,324.166L10610.78,324.166C10690.46,324.166 10755.151,388.857 10755.151,468.538ZM10323.418,417.171L10326.515,437.161C10331.987,472.482 10362.392,498.54 10398.135,498.54L10532.582,498.54C10567.865,498.54 10598.02,473.132 10604.006,438.36L10607.56,417.711C10608.244,413.738 10607.143,409.665 10604.55,406.578C10601.958,403.491 10598.137,401.702 10594.105,401.689L10568.061,401.604C10561.653,401.583 10556.086,406.008 10554.661,412.256L10550.796,429.201C10549.269,438.068 10541.579,444.547 10532.582,444.547L10398.135,444.547C10389.02,444.547 10381.267,437.902 10379.871,428.895L10377.426,413.111C10376.396,406.46 10370.687,401.543 10363.957,401.51L10337.023,401.375C10333.012,401.355 10329.194,403.094 10326.576,406.134C10323.958,409.173 10322.804,413.207 10323.418,417.171ZM10624.96,701.428L10608.01,602.96C10599.711,554.748 10557.898,519.518 10508.977,519.518L10422.144,519.518C10372.585,519.518 10330.426,555.648 10322.839,604.623L10307.572,703.169C10302.871,733.512 10311.666,764.394 10331.647,787.709C10351.628,811.024 10380.799,824.442 10411.505,824.442L10521.312,824.442C10552.325,824.442 10581.758,810.754 10601.741,787.037C10621.724,763.32 10630.221,731.992 10624.96,701.428ZM10556.997,624.883L10571.236,707.601C10573.924,723.216 10569.583,739.222 10559.373,751.339C10549.163,763.456 10534.126,770.45 10518.281,770.45L10414.485,770.45C10398.797,770.45 10383.893,763.594 10373.685,751.682C10363.476,739.771 10358.983,723.993 10361.385,708.49L10374.179,625.907C10378.85,595.755 10404.806,573.511 10435.317,573.511L10496.026,573.511C10526.145,573.511 10551.887,595.201 10556.997,624.883ZM10518.185,644.084L10485.169,677.1C10481.077,681.192 10474.443,681.192 10470.352,677.1L10460.989,667.737C10456.897,663.646 10456.897,657.012 10460.989,652.92C10470.018,643.891 10485.161,628.748 10494.002,619.902C10495.699,618.205 10496.43,615.769 10495.948,613.418C10495.466,611.068 10493.836,609.116 10491.609,608.224C10483.596,604.979 10474.84,603.193 10465.67,603.193C10427.463,603.193 10396.444,634.212 10396.444,672.419C10396.444,710.626 10427.463,741.645 10465.67,741.645C10503.877,741.645 10534.896,710.626 10534.896,672.419C10534.896,663.249 10533.11,654.493 10529.869,646.479C10528.976,644.25 10527.024,642.619 10524.672,642.137C10522.319,641.655 10519.882,642.386 10518.185,644.084Z" style="fill:rgb(0,214,156);"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-12501.456547,726.774609)">
<g transform="matrix(1,0,0,1,-151.472291,0)">
<g transform="matrix(0.683604,0,0,0.683604,10912.013984,-1075.663646)">
<g transform="matrix(0.764685,0,0,0.764685,1814.51336,-94.801291)">
<g transform="matrix(0.843817,0,0,1,973.42738,670.673266)">
<path d="M996.456,815.382C1010.891,886.141 987.579,958.668 932.752,1013.576C877.925,1068.484 797.174,1100.174 712.085,1100.174C614.422,1100.174 508.13,1100.174 410.814,1100.174C326.571,1100.174 246.534,1069.108 191.713,1015.131C136.893,961.155 112.765,889.659 125.662,819.41C139.686,743.025 154.576,661.927 167.549,591.266C188.366,477.884 304.034,394.237 440.005,394.237C516.746,394.237 601.794,394.237 678.242,394.237C812.464,394.237 927.183,475.799 949.952,587.417C964.298,657.739 980.831,738.787 996.456,815.382ZM809.991,638.17C795.972,569.452 725.344,519.237 642.709,519.237C589.643,519.237 529.429,519.237 476.147,519.237C392.435,519.237 321.222,570.735 308.406,640.54C297.616,699.31 284.584,770.291 273.304,831.73C266.715,867.62 279.042,904.148 307.05,931.725C335.058,959.302 375.949,975.174 418.99,975.174C507.403,975.174 614.937,975.174 703.769,975.174C747.242,975.174 788.498,958.983 816.51,930.93C844.521,902.878 856.431,865.823 849.056,829.672C836.451,767.879 821.939,696.744 809.991,638.17Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.843817,0,0,-1,973.42738,1410.581134)">
<path d="M169.137,582.616C167.452,591.793 170.619,601.132 177.801,608.169C184.983,615.205 195.46,619.231 206.465,619.185C230.149,619.085 258.821,618.965 280.361,618.874C298.825,618.797 314.488,607.413 317.315,592.016C320.486,574.745 324.024,555.473 324.024,555.473C327.852,534.621 349.125,519.237 374.132,519.237L743.005,519.237C767.69,519.237 788.789,534.237 792.976,554.765C792.976,554.765 798.715,575.995 803.581,593.996C807.492,608.461 822.764,618.705 840.347,618.656C860.96,618.6 888.653,618.523 911.802,618.459C922.863,618.429 933.347,614.288 940.46,607.14C947.573,599.993 950.594,590.564 948.718,581.365C944.059,558.529 938.966,533.56 938.966,533.56C922.544,453.06 839.808,394.237 743.005,394.237L374.132,394.237C276.068,394.237 192.647,454.564 177.634,536.336C177.634,536.336 173.216,560.398 169.137,582.616Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.923041,-0,0,0.923041,854.504081,621.345248)">
<path d="M771.961,792.978C776.219,788.719 782.332,786.884 788.231,788.093C794.131,789.302 799.029,793.394 801.268,798.984C809.395,819.084 813.877,841.045 813.877,864.045C813.877,959.873 736.076,1037.674 640.248,1037.674C544.419,1037.674 466.619,959.873 466.619,864.045C466.619,768.216 544.419,690.416 640.248,690.416C663.247,690.416 685.208,694.897 705.305,703.034C710.892,705.272 714.981,710.167 716.189,716.063C717.398,721.96 715.564,728.068 711.308,732.324C689.133,754.513 651.152,792.493 628.507,815.139C618.244,825.402 618.244,842.041 628.507,852.303C635.961,859.758 644.535,868.331 651.989,875.786C662.252,886.048 678.891,886.048 689.153,875.786C711.799,853.14 749.779,815.16 771.961,792.978Z" style="fill:rgb(0,214,156);"/>
</g>
</g>
</g>
<g transform="matrix(0.368856,0,0,0.368856,11808.280456,-883.148415)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:none;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-11884.181719,726.774609)">
<g transform="matrix(1,0,0,1,86.762524,160.29105)">
<g transform="matrix(0.30616,0,0,0.30616,11159.078973,-901.97185)">
<g transform="matrix(0.764685,0,0,0.764685,1814.51336,-94.801291)">
<g transform="matrix(0.843817,0,0,1,973.42738,670.673266)">
<path d="M996.456,815.382C1010.891,886.141 987.579,958.668 932.752,1013.576C877.925,1068.484 797.174,1100.174 712.085,1100.174C614.422,1100.174 508.13,1100.174 410.814,1100.174C326.571,1100.174 246.534,1069.108 191.713,1015.131C136.893,961.155 112.765,889.659 125.662,819.41C139.686,743.025 154.576,661.927 167.549,591.266C188.366,477.884 304.034,394.237 440.005,394.237C516.746,394.237 601.794,394.237 678.242,394.237C812.464,394.237 927.183,475.799 949.952,587.417C964.298,657.739 980.831,738.787 996.456,815.382ZM809.991,638.17C795.972,569.452 725.344,519.237 642.709,519.237C589.643,519.237 529.429,519.237 476.147,519.237C392.435,519.237 321.222,570.735 308.406,640.54C297.616,699.31 284.584,770.291 273.304,831.73C266.715,867.62 279.042,904.148 307.05,931.725C335.058,959.302 375.949,975.174 418.99,975.174C507.403,975.174 614.937,975.174 703.769,975.174C747.242,975.174 788.498,958.983 816.51,930.93C844.521,902.878 856.431,865.823 849.056,829.672C836.451,767.879 821.939,696.744 809.991,638.17Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.843817,0,0,-1,973.42738,1410.581134)">
<path d="M169.137,582.616C167.452,591.793 170.619,601.132 177.801,608.169C184.983,615.205 195.46,619.231 206.465,619.185C230.149,619.085 258.821,618.965 280.361,618.874C298.825,618.797 314.488,607.413 317.315,592.016C320.486,574.745 324.024,555.473 324.024,555.473C327.852,534.621 349.125,519.237 374.132,519.237L743.005,519.237C767.69,519.237 788.789,534.237 792.976,554.765C792.976,554.765 798.715,575.995 803.581,593.996C807.492,608.461 822.764,618.705 840.347,618.656C860.96,618.6 888.653,618.523 911.802,618.459C922.863,618.429 933.347,614.288 940.46,607.14C947.573,599.993 950.594,590.564 948.718,581.365C944.059,558.529 938.966,533.56 938.966,533.56C922.544,453.06 839.808,394.237 743.005,394.237L374.132,394.237C276.068,394.237 192.647,454.564 177.634,536.336C177.634,536.336 173.216,560.398 169.137,582.616Z" style="fill:rgb(23,66,255);"/>
</g>
<g transform="matrix(0.923041,-0,0,0.923041,854.504081,621.345248)">
<path d="M771.961,792.978C776.219,788.719 782.332,786.884 788.231,788.093C794.131,789.302 799.029,793.394 801.268,798.984C809.395,819.084 813.877,841.045 813.877,864.045C813.877,959.873 736.076,1037.674 640.248,1037.674C544.419,1037.674 466.619,959.873 466.619,864.045C466.619,768.216 544.419,690.416 640.248,690.416C663.247,690.416 685.208,694.897 705.305,703.034C710.892,705.272 714.981,710.167 716.189,716.063C717.398,721.96 715.564,728.068 711.308,732.324C689.133,754.513 651.152,792.493 628.507,815.139C618.244,825.402 618.244,842.041 628.507,852.303C635.961,859.758 644.535,868.331 651.989,875.786C662.252,886.048 678.891,886.048 689.153,875.786C711.799,853.14 749.779,815.16 771.961,792.978Z" style="fill:rgb(0,214,156);"/>
</g>
</g>
</g>
<g transform="matrix(0.368856,0,0,0.368856,10952.770812,-1043.439465)">
<rect x="2289.913" y="423.943" width="1388.075" height="1388.075" style="fill:none;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

+34 -34
View File
@@ -1,34 +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
**/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
+26 -26
View File
@@ -1,26 +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>13.0</string>
</dict>
</plist>
<?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>13.0</string>
</dict>
</plist>
+1 -1
View File
@@ -1 +1 @@
#include "Generated.xcconfig"
#include "Generated.xcconfig"
+1 -1
View File
@@ -1 +1 @@
#include "Generated.xcconfig"
#include "Generated.xcconfig"
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -1,8 +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>
<?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>
@@ -1,8 +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>
<?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>
@@ -1,101 +1,101 @@
<?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"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
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"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
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>
<?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"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
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"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
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>
+7 -7
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
@@ -1,8 +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>
<?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>
@@ -1,8 +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>
<?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>
+13 -13
View File
@@ -1,13 +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)
}
}
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)
}
}
@@ -1,122 +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"
}
}
{
"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"
}
}
+23 -23
View File
@@ -1,23 +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"
}
}
{
"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"
}
}
+4 -4
View File
@@ -1,5 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
# 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.
+37 -37
View File
@@ -1,37 +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>
<?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>
+26 -26
View File
@@ -1,26 +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>
<?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>
+1 -1
View File
@@ -1 +1 @@
#import "GeneratedPluginRegistrant.h"
#import "GeneratedPluginRegistrant.h"
+12 -12
View File
@@ -1,12 +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.
}
}
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.
}
}
+93 -93
View File
@@ -1,93 +1,93 @@
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import '../models/registered_device.dart';
const _tableName = 'siab_devices';
class SiabDatabase {
static Database? _db;
static Future<Database> get database async {
if (_db != null) return _db!;
_db = await _init();
return _db!;
}
static Future<Database> _init() async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, 'siab_devices.db');
return openDatabase(
path,
version: 2,
onCreate: (db, version) async {
await db.execute('''
CREATE TABLE $_tableName (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uuid TEXT NOT NULL UNIQUE,
label TEXT NOT NULL
)
''');
},
onUpgrade: (db, oldVersion, newVersion) async {
// Simple destructive migration: drop old table and recreate with new schema.
if (oldVersion < 2) {
await db.execute('DROP TABLE IF EXISTS $_tableName');
await db.execute('''
CREATE TABLE $_tableName (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uuid TEXT NOT NULL UNIQUE,
label TEXT NOT NULL
)
''');
}
},
);
}
Future<int> insert(RegisteredDevice device) async {
final db = await database;
return db.insert(
_tableName,
device.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
Future<List<RegisteredDevice>> getAll() async {
final db = await database;
final maps = await db.query(_tableName, orderBy: 'label ASC');
return maps.map(RegisteredDevice.fromMap).toList();
}
Future<RegisteredDevice?> getByUuid(String uuid) async {
final db = await database;
final maps = await db.query(
_tableName,
where: 'uuid = ?',
whereArgs: [uuid],
);
if (maps.isEmpty) return null;
return RegisteredDevice.fromMap(maps.first);
}
Future<int> update(RegisteredDevice device) async {
if (device.id == null) return 0;
final db = await database;
return db.update(
_tableName,
device.toMap(),
where: 'id = ?',
whereArgs: [device.id],
);
}
Future<int> delete(int id) async {
final db = await database;
return db.delete(_tableName, where: 'id = ?', whereArgs: [id]);
}
Future<int> deleteByUuid(String uuid) async {
final db = await database;
return db.delete(_tableName, where: 'uuid = ?', whereArgs: [uuid]);
}
}
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import '../models/registered_device.dart';
const _tableName = 'siab_devices';
class SiabDatabase {
static Database? _db;
static Future<Database> get database async {
if (_db != null) return _db!;
_db = await _init();
return _db!;
}
static Future<Database> _init() async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, 'siab_devices.db');
return openDatabase(
path,
version: 2,
onCreate: (db, version) async {
await db.execute('''
CREATE TABLE $_tableName (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uuid TEXT NOT NULL UNIQUE,
label TEXT NOT NULL
)
''');
},
onUpgrade: (db, oldVersion, newVersion) async {
// Simple destructive migration: drop old table and recreate with new schema.
if (oldVersion < 2) {
await db.execute('DROP TABLE IF EXISTS $_tableName');
await db.execute('''
CREATE TABLE $_tableName (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uuid TEXT NOT NULL UNIQUE,
label TEXT NOT NULL
)
''');
}
},
);
}
Future<int> insert(RegisteredDevice device) async {
final db = await database;
return db.insert(
_tableName,
device.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
Future<List<RegisteredDevice>> getAll() async {
final db = await database;
final maps = await db.query(_tableName, orderBy: 'label ASC');
return maps.map(RegisteredDevice.fromMap).toList();
}
Future<RegisteredDevice?> getByUuid(String uuid) async {
final db = await database;
final maps = await db.query(
_tableName,
where: 'uuid = ?',
whereArgs: [uuid],
);
if (maps.isEmpty) return null;
return RegisteredDevice.fromMap(maps.first);
}
Future<int> update(RegisteredDevice device) async {
if (device.id == null) return 0;
final db = await database;
return db.update(
_tableName,
device.toMap(),
where: 'id = ?',
whereArgs: [device.id],
);
}
Future<int> delete(int id) async {
final db = await database;
return db.delete(_tableName, where: 'id = ?', whereArgs: [id]);
}
Future<int> deleteByUuid(String uuid) async {
final db = await database;
return db.delete(_tableName, where: 'uuid = ?', whereArgs: [uuid]);
}
}
+97 -97
View File
@@ -1,97 +1,97 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'services/ble_service.dart';
import 'screens/main_shell.dart';
void main() {
runApp(const SIABApp());
}
class SIABApp extends StatelessWidget {
const SIABApp({super.key});
@override
Widget build(BuildContext context) {
final colorScheme = ColorScheme.fromSeed(
seedColor: const Color(0xFF2563EB),
brightness: Brightness.light,
);
return ChangeNotifierProvider(
create: (_) => BLEService(),
child: MaterialApp(
title: 'SIAB Scale',
theme: ThemeData(
colorScheme: colorScheme,
scaffoldBackgroundColor: const Color(0xFFF4F8FF),
useMaterial3: true,
appBarTheme: const AppBarTheme(
centerTitle: false,
backgroundColor: Color(0xFFF8FBFF),
foregroundColor: Color(0xFF0F172A),
elevation: 0,
surfaceTintColor: Colors.transparent,
),
cardTheme: CardThemeData(
color: Colors.white,
elevation: 0,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
),
),
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
backgroundColor: const Color(0xFF2563EB),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2563EB),
foregroundColor: Colors.white,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: const Color(0xFF2563EB),
side: const BorderSide(color: Color(0x663B82F6)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: const Color(0xFF2563EB),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14),
),
),
),
snackBarTheme: SnackBarThemeData(
behavior: SnackBarBehavior.floating,
backgroundColor: const Color(0xFF0F172A),
contentTextStyle: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
),
themeMode: ThemeMode.light,
home: const MainShell(),
debugShowCheckedModeBanner: false,
),
);
}
}
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'services/ble_service.dart';
import 'screens/main_shell.dart';
void main() {
runApp(const SIABApp());
}
class SIABApp extends StatelessWidget {
const SIABApp({super.key});
@override
Widget build(BuildContext context) {
final colorScheme = ColorScheme.fromSeed(
seedColor: const Color(0xFF2563EB),
brightness: Brightness.light,
);
return ChangeNotifierProvider(
create: (_) => BLEService(),
child: MaterialApp(
title: 'SIAB Scale',
theme: ThemeData(
colorScheme: colorScheme,
scaffoldBackgroundColor: const Color(0xFFF4F8FF),
useMaterial3: true,
appBarTheme: const AppBarTheme(
centerTitle: false,
backgroundColor: Color(0xFFF8FBFF),
foregroundColor: Color(0xFF0F172A),
elevation: 0,
surfaceTintColor: Colors.transparent,
),
cardTheme: CardThemeData(
color: Colors.white,
elevation: 0,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
),
),
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
backgroundColor: const Color(0xFF2563EB),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2563EB),
foregroundColor: Colors.white,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: const Color(0xFF2563EB),
side: const BorderSide(color: Color(0x663B82F6)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: const Color(0xFF2563EB),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14),
),
),
),
snackBarTheme: SnackBarThemeData(
behavior: SnackBarBehavior.floating,
backgroundColor: const Color(0xFF0F172A),
contentTextStyle: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
),
themeMode: ThemeMode.light,
home: const MainShell(),
debugShowCheckedModeBanner: false,
),
);
}
}
+41 -41
View File
@@ -1,41 +1,41 @@
/// A SIAB device registered in local SQLite with a user-assigned label.
/// Stores only a user label (\"Label ID\") and the device UUID.
class RegisteredDevice {
final int? id;
final String uuid;
final String label;
RegisteredDevice({
this.id,
required this.uuid,
required this.label,
});
Map<String, dynamic> toMap() {
return {
if (id != null) 'id': id,
'uuid': uuid,
'label': label,
};
}
static RegisteredDevice fromMap(Map<String, dynamic> map) {
return RegisteredDevice(
id: map['id'] as int?,
uuid: map['uuid'] as String,
label: map['label'] as String,
);
}
RegisteredDevice copyWith({
int? id,
String? uuid,
String? label,
}) {
return RegisteredDevice(
id: id ?? this.id,
uuid: uuid ?? this.uuid,
label: label ?? this.label,
);
}
}
/// A SIAB device registered in local SQLite with a user-assigned label.
/// Stores only a user label (\"Label ID\") and the device UUID.
class RegisteredDevice {
final int? id;
final String uuid;
final String label;
RegisteredDevice({
this.id,
required this.uuid,
required this.label,
});
Map<String, dynamic> toMap() {
return {
if (id != null) 'id': id,
'uuid': uuid,
'label': label,
};
}
static RegisteredDevice fromMap(Map<String, dynamic> map) {
return RegisteredDevice(
id: map['id'] as int?,
uuid: map['uuid'] as String,
label: map['label'] as String,
);
}
RegisteredDevice copyWith({
int? id,
String? uuid,
String? label,
}) {
return RegisteredDevice(
id: id ?? this.id,
uuid: uuid ?? this.uuid,
label: label ?? this.label,
);
}
}
+318 -318
View File
@@ -1,318 +1,318 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../database/siab_database.dart';
import '../models/registered_device.dart';
import '../services/ble_service.dart';
import '../siab_config.dart';
class DevicesScreen extends StatefulWidget {
const DevicesScreen({super.key});
@override
State<DevicesScreen> createState() => _DevicesScreenState();
}
class _DevicesScreenState extends State<DevicesScreen> {
final _db = SiabDatabase();
List<RegisteredDevice> _saved = [];
List<SiabScanResult> _scanResults = [];
bool _loading = false;
Future<void> _loadSaved() async {
setState(() => _loading = true);
_saved = await _db.getAll();
setState(() => _loading = false);
}
Future<void> _scan() async {
final ble = context.read<BLEService>();
setState(() => _scanResults = []);
final list = await ble.scanForAllSiabDevices();
setState(() => _scanResults = list);
}
Future<void> _register( SiabScanResult result, String label) async {
await _db.insert(RegisteredDevice(
uuid: result.address,
label: label.isEmpty ? result.address : label,
));
await _loadSaved();
}
Future<void> _connectToScanResult(SiabScanResult result) async {
final ble = context.read<BLEService>();
final ok = await ble.connectToDevice(result.device);
if (mounted && !ok) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Connection failed'), backgroundColor: Colors.red),
);
} else if (mounted && ok) {
await Future.delayed(const Duration(seconds: 2));
if (mounted && ble.packetCount == 0) ble.tryStartCommands();
await _loadSaved();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Connected'), backgroundColor: Colors.green),
);
}
}
}
Future<void> _connectToSaved(RegisteredDevice device) async {
final ble = context.read<BLEService>();
final ok = await ble.connectToAddress(device.uuid);
if (mounted && !ok) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Device not found or connection failed'), backgroundColor: Colors.red),
);
} else if (mounted && ok) {
await Future.delayed(const Duration(seconds: 2));
if (mounted && ble.packetCount == 0) ble.tryStartCommands();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Connected'), backgroundColor: Colors.green),
);
}
}
}
Future<void> _unregisterDevice(RegisteredDevice device) async {
final confirmed = await showDialog<bool>(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('Unregister device'),
content: Text(
'Remove "${device.label}" (${device.uuid}) from registered devices?',
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx, false),
child: const Text('Cancel'),
),
FilledButton(
onPressed: () => Navigator.pop(ctx, true),
child: const Text('Unregister'),
),
],
),
);
if (confirmed != true) return;
if (device.id != null) {
await _db.delete(device.id!);
} else {
await _db.deleteByUuid(device.uuid);
}
await _loadSaved();
}
@override
void initState() {
super.initState();
_loadSaved();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('SIAB SCALE'),
actions: [
IconButton(
onPressed: _loading ? null : _loadSaved,
icon: const Icon(Icons.refresh),
),
],
),
body: Consumer<BLEService>(
builder: (context, ble, _) {
return ListView(
padding: const EdgeInsets.all(16),
children: [
// Scan section at top
const Text('Daftar Timbangan (scan)', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
OutlinedButton.icon(
onPressed: ble.isScanning ? null : () async { await _scan(); },
icon: ble.isScanning
? const SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.bluetooth_searching, size: 20),
label: Text(ble.isScanning ? 'Scanning...' : 'Scan Timbangan'),
),
const SizedBox(height: 12),
if (_scanResults.isEmpty && !ble.isScanning)
const Card(child: Padding(
padding: EdgeInsets.all(16),
child: Text('Tap "Scan Timbangan" lihat melihat timbangan di sekitar.'),
))
else
..._scanResults.map((r) {
RegisteredDevice? registered;
for (final d in _saved) {
if (d.uuid == r.address) { registered = d; break; }
}
final labelId = registered?.label;
final hasLabel = labelId != null && labelId.isNotEmpty;
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_ListRow(label: 'NAMA', value: labelId ?? '—'),
_ListRow(label: 'ID', value: r.device.remoteId.toString()),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (!hasLabel)
Padding(
padding: const EdgeInsets.only(right: 8),
child: TextButton.icon(
onPressed: () => _showRegisterDialog(r),
icon: const Icon(Icons.app_registration, size: 18),
label: const Text('Register'),
),
),
TextButton.icon(
onPressed: ble.isConnecting ? null : () => _connectToScanResult(r),
icon: const Icon(Icons.link, size: 18),
label: const Text('Connect'),
),
],
),
],
),
),
);
}),
const SizedBox(height: 24),
// Registered devices below scan
const Text('Registered devices (saved)', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
if (_loading)
const Center(child: CircularProgressIndicator())
else if (_saved.isEmpty)
const Card(child: Padding(
padding: EdgeInsets.all(16),
child: Text('No registered devices. Scan and register above.'),
))
else
..._saved.map((d) => Card(
margin: const EdgeInsets.only(bottom: 8),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_ListRow(label: 'NAMA', value: d.label),
_ListRow(label: 'ID', value: d.uuid),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton.icon(
onPressed: () => _unregisterDevice(d),
icon: const Icon(Icons.delete_outline, size: 18),
label: const Text('Unregister'),
),
const SizedBox(width: 8),
if (ble.isConnected && ble.deviceAddress == d.uuid)
const Icon(Icons.bluetooth_connected, color: Colors.green, size: 28)
else
TextButton.icon(
onPressed: ble.isConnecting ? null : () => _connectToSaved(d),
icon: const Icon(Icons.link, size: 18),
label: const Text('Connect'),
),
],
),
],
),
),
)),
],
);
},
),
);
}
void _showRegisterDialog(SiabScanResult result) {
final controller = TextEditingController(
text: result.name.isNotEmpty ? result.name : SiabConfig.deviceName,
);
showDialog<void>(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('Register device'),
content: TextField(
controller: controller,
decoration: const InputDecoration(
labelText: 'Nama',
hintText: 'contoh : Scale 1, TIMBANGAN 1',
),
autofocus: true,
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: const Text('Cancel'),
),
FilledButton(
onPressed: () async {
final label = controller.text.trim();
await _register(result, label.isEmpty ? result.address : label);
if (mounted) Navigator.pop(ctx);
},
child: const Text('Save'),
),
],
),
);
}
}
class _ListRow extends StatelessWidget {
final String label;
final String value;
const _ListRow({required this.label, required this.value});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 110,
child: Text(
'$label:',
style: TextStyle(
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.8),
fontSize: 13,
),
),
),
Expanded(
child: SelectableText(
value,
style: const TextStyle(fontSize: 13),
),
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../database/siab_database.dart';
import '../models/registered_device.dart';
import '../services/ble_service.dart';
import '../siab_config.dart';
class DevicesScreen extends StatefulWidget {
const DevicesScreen({super.key});
@override
State<DevicesScreen> createState() => _DevicesScreenState();
}
class _DevicesScreenState extends State<DevicesScreen> {
final _db = SiabDatabase();
List<RegisteredDevice> _saved = [];
List<SiabScanResult> _scanResults = [];
bool _loading = false;
Future<void> _loadSaved() async {
setState(() => _loading = true);
_saved = await _db.getAll();
setState(() => _loading = false);
}
Future<void> _scan() async {
final ble = context.read<BLEService>();
setState(() => _scanResults = []);
final list = await ble.scanForAllSiabDevices();
setState(() => _scanResults = list);
}
Future<void> _register( SiabScanResult result, String label) async {
await _db.insert(RegisteredDevice(
uuid: result.address,
label: label.isEmpty ? result.address : label,
));
await _loadSaved();
}
Future<void> _connectToScanResult(SiabScanResult result) async {
final ble = context.read<BLEService>();
final ok = await ble.connectToDevice(result.device);
if (mounted && !ok) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Connection failed'), backgroundColor: Colors.red),
);
} else if (mounted && ok) {
await Future.delayed(const Duration(seconds: 2));
if (mounted && ble.packetCount == 0) ble.tryStartCommands();
await _loadSaved();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Connected'), backgroundColor: Colors.green),
);
}
}
}
Future<void> _connectToSaved(RegisteredDevice device) async {
final ble = context.read<BLEService>();
final ok = await ble.connectToAddress(device.uuid);
if (mounted && !ok) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Device not found or connection failed'), backgroundColor: Colors.red),
);
} else if (mounted && ok) {
await Future.delayed(const Duration(seconds: 2));
if (mounted && ble.packetCount == 0) ble.tryStartCommands();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Connected'), backgroundColor: Colors.green),
);
}
}
}
Future<void> _unregisterDevice(RegisteredDevice device) async {
final confirmed = await showDialog<bool>(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('Unregister device'),
content: Text(
'Remove "${device.label}" (${device.uuid}) from registered devices?',
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx, false),
child: const Text('Cancel'),
),
FilledButton(
onPressed: () => Navigator.pop(ctx, true),
child: const Text('Unregister'),
),
],
),
);
if (confirmed != true) return;
if (device.id != null) {
await _db.delete(device.id!);
} else {
await _db.deleteByUuid(device.uuid);
}
await _loadSaved();
}
@override
void initState() {
super.initState();
_loadSaved();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('SIAB SCALE'),
actions: [
IconButton(
onPressed: _loading ? null : _loadSaved,
icon: const Icon(Icons.refresh),
),
],
),
body: Consumer<BLEService>(
builder: (context, ble, _) {
return ListView(
padding: const EdgeInsets.all(16),
children: [
// Scan section at top
const Text('Daftar Timbangan (scan)', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
OutlinedButton.icon(
onPressed: ble.isScanning ? null : () async { await _scan(); },
icon: ble.isScanning
? const SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.bluetooth_searching, size: 20),
label: Text(ble.isScanning ? 'Scanning...' : 'Scan Timbangan'),
),
const SizedBox(height: 12),
if (_scanResults.isEmpty && !ble.isScanning)
const Card(child: Padding(
padding: EdgeInsets.all(16),
child: Text('Tap "Scan Timbangan" lihat melihat timbangan di sekitar.'),
))
else
..._scanResults.map((r) {
RegisteredDevice? registered;
for (final d in _saved) {
if (d.uuid == r.address) { registered = d; break; }
}
final labelId = registered?.label;
final hasLabel = labelId != null && labelId.isNotEmpty;
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_ListRow(label: 'NAMA', value: labelId ?? '—'),
_ListRow(label: 'ID', value: r.device.remoteId.toString()),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (!hasLabel)
Padding(
padding: const EdgeInsets.only(right: 8),
child: TextButton.icon(
onPressed: () => _showRegisterDialog(r),
icon: const Icon(Icons.app_registration, size: 18),
label: const Text('Register'),
),
),
TextButton.icon(
onPressed: ble.isConnecting ? null : () => _connectToScanResult(r),
icon: const Icon(Icons.link, size: 18),
label: const Text('Connect'),
),
],
),
],
),
),
);
}),
const SizedBox(height: 24),
// Registered devices below scan
const Text('Registered devices (saved)', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
if (_loading)
const Center(child: CircularProgressIndicator())
else if (_saved.isEmpty)
const Card(child: Padding(
padding: EdgeInsets.all(16),
child: Text('No registered devices. Scan and register above.'),
))
else
..._saved.map((d) => Card(
margin: const EdgeInsets.only(bottom: 8),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_ListRow(label: 'NAMA', value: d.label),
_ListRow(label: 'ID', value: d.uuid),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton.icon(
onPressed: () => _unregisterDevice(d),
icon: const Icon(Icons.delete_outline, size: 18),
label: const Text('Unregister'),
),
const SizedBox(width: 8),
if (ble.isConnected && ble.deviceAddress == d.uuid)
const Icon(Icons.bluetooth_connected, color: Colors.green, size: 28)
else
TextButton.icon(
onPressed: ble.isConnecting ? null : () => _connectToSaved(d),
icon: const Icon(Icons.link, size: 18),
label: const Text('Connect'),
),
],
),
],
),
),
)),
],
);
},
),
);
}
void _showRegisterDialog(SiabScanResult result) {
final controller = TextEditingController(
text: result.name.isNotEmpty ? result.name : SiabConfig.deviceName,
);
showDialog<void>(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('Register device'),
content: TextField(
controller: controller,
decoration: const InputDecoration(
labelText: 'Nama',
hintText: 'contoh : Scale 1, TIMBANGAN 1',
),
autofocus: true,
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: const Text('Cancel'),
),
FilledButton(
onPressed: () async {
final label = controller.text.trim();
await _register(result, label.isEmpty ? result.address : label);
if (ctx.mounted) Navigator.pop(ctx);
},
child: const Text('Save'),
),
],
),
);
}
}
class _ListRow extends StatelessWidget {
final String label;
final String value;
const _ListRow({required this.label, required this.value});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 110,
child: Text(
'$label:',
style: TextStyle(
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.8),
fontSize: 13,
),
),
),
Expanded(
child: SelectableText(
value,
style: const TextStyle(fontSize: 13),
),
),
],
),
);
}
}
+144 -143
View File
@@ -1,143 +1,144 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../services/ble_service.dart';
import '../widgets/data_packet_card.dart';
import '../widgets/statistics_card.dart';
import '../widgets/connection_card.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final ScrollController _scrollController = ScrollController();
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('SIAB Scale'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
actions: [
Consumer<BLEService>(
builder: (context, ble, _) {
if (ble.isConnected) {
return IconButton(
icon: const Icon(Icons.delete_outline),
tooltip: 'Clear Data',
onPressed: () {
ble.clearData();
},
);
}
return const SizedBox.shrink();
},
),
],
),
body: Consumer<BLEService>(
builder: (context, ble, _) {
return Column(
children: [
// Connection Card
ConnectionCard(ble: ble),
// Statistics Card
if (ble.isConnected) StatisticsCard(ble: ble),
// Data Packets List
Expanded(
child: ble.isConnected && ble.dataPackets.isNotEmpty
? ListView.builder(
controller: _scrollController,
padding: const EdgeInsets.all(8),
itemCount: ble.dataPackets.length,
reverse: true, // Show newest first
itemBuilder: (context, index) {
final packet = ble.dataPackets[ble.dataPackets.length - 1 - index];
return DataPacketCard(packet: packet);
},
)
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
ble.isConnected
? Icons.bluetooth_connected
: Icons.bluetooth_disabled,
size: 64,
color: Colors.grey,
),
const SizedBox(height: 16),
Text(
ble.isConnected
? 'Waiting for data...'
: 'Not connected',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: Colors.grey,
),
),
if (ble.isConnected) ...[
const SizedBox(height: 8),
const Text(
'Data packets will appear here',
style: TextStyle(color: Colors.grey),
),
],
],
),
),
),
],
);
},
),
floatingActionButton: Consumer<BLEService>(
builder: (context, ble, _) {
if (ble.isConnecting || ble.isScanning) {
return const FloatingActionButton(
onPressed: null,
child: CircularProgressIndicator(color: Colors.white),
);
}
if (ble.isConnected) {
return FloatingActionButton(
onPressed: () async {
await ble.disconnect();
ble.clearData();
},
backgroundColor: Colors.red,
child: const Icon(Icons.bluetooth_disabled),
);
}
return FloatingActionButton(
onPressed: () async {
final success = await ble.autoConnect();
if (!success && mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Koneksi ke timbangan gagal'),
backgroundColor: Colors.red,
),
);
}
},
child: const Icon(Icons.bluetooth_searching),
);
},
),
);
}
}
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../services/ble_service.dart';
import '../widgets/data_packet_card.dart';
import '../widgets/statistics_card.dart';
import '../widgets/connection_card.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final ScrollController _scrollController = ScrollController();
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('SIAB Scale'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
actions: [
Consumer<BLEService>(
builder: (context, ble, _) {
if (ble.isConnected) {
return IconButton(
icon: const Icon(Icons.delete_outline),
tooltip: 'Clear Data',
onPressed: () {
ble.clearData();
},
);
}
return const SizedBox.shrink();
},
),
],
),
body: Consumer<BLEService>(
builder: (context, ble, _) {
return Column(
children: [
// Connection Card
ConnectionCard(ble: ble),
// Statistics Card
if (ble.isConnected) StatisticsCard(ble: ble),
// Data Packets List
Expanded(
child: ble.isConnected && ble.dataPackets.isNotEmpty
? ListView.builder(
controller: _scrollController,
padding: const EdgeInsets.all(8),
itemCount: ble.dataPackets.length,
reverse: true, // Show newest first
itemBuilder: (context, index) {
final packet = ble.dataPackets[ble.dataPackets.length - 1 - index];
return DataPacketCard(packet: packet);
},
)
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
ble.isConnected
? Icons.bluetooth_connected
: Icons.bluetooth_disabled,
size: 64,
color: Colors.grey,
),
const SizedBox(height: 16),
Text(
ble.isConnected
? 'Waiting for data...'
: 'Not connected',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: Colors.grey,
),
),
if (ble.isConnected) ...[
const SizedBox(height: 8),
const Text(
'Data packets will appear here',
style: TextStyle(color: Colors.grey),
),
],
],
),
),
),
],
);
},
),
floatingActionButton: Consumer<BLEService>(
builder: (_, ble, __) {
if (ble.isConnecting || ble.isScanning) {
return const FloatingActionButton(
onPressed: null,
child: CircularProgressIndicator(color: Colors.white),
);
}
if (ble.isConnected) {
return FloatingActionButton(
onPressed: () async {
await ble.disconnect();
ble.clearData();
},
backgroundColor: Colors.red,
child: const Icon(Icons.bluetooth_disabled),
);
}
return FloatingActionButton(
onPressed: () async {
final scaffoldMessenger = ScaffoldMessenger.of(context);
final success = await ble.autoConnect();
if (!success && mounted) {
scaffoldMessenger.showSnackBar(
const SnackBar(
content: Text('Koneksi ke timbangan gagal'),
backgroundColor: Colors.red,
),
);
}
},
child: const Icon(Icons.bluetooth_searching),
);
},
),
);
}
}
+206 -206
View File
@@ -1,206 +1,206 @@
import 'dart:ui' show ImageFilter;
import 'package:flutter/material.dart';
import 'devices_screen.dart';
import 'timbang_screen.dart';
/// Root scaffold with bottom nav: Devices and Timbang (scale display).
class MainShell extends StatefulWidget {
const MainShell({super.key});
@override
State<MainShell> createState() => _MainShellState();
}
class _MainShellState extends State<MainShell> {
int _index = 0;
static const _tabs = [
(label: 'Devices', icon: Icons.list_alt),
(label: 'Timbang', icon: Icons.monitor_weight),
];
@override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
body: IndexedStack(
index: _index,
children: const [
DevicesScreen(),
TimbangScreen(),
],
),
bottomNavigationBar: _FloatingGlassNavigationBar(
currentIndex: _index,
tabs: _tabs,
onTap: (i) => setState(() => _index = i),
),
);
}
}
class _FloatingGlassNavigationBar extends StatelessWidget {
const _FloatingGlassNavigationBar({
required this.currentIndex,
required this.tabs,
required this.onTap,
});
final int currentIndex;
final List<({String label, IconData icon})> tabs;
final ValueChanged<int> onTap;
@override
Widget build(BuildContext context) {
return SafeArea(
minimum: const EdgeInsets.fromLTRB(20, 0, 20, 18),
child: ClipRRect(
borderRadius: BorderRadius.circular(32),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 24, sigmaY: 24),
child: Container(
height: 72,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.white.withValues(alpha: 0.84),
Colors.white.withValues(alpha: 0.62),
],
),
borderRadius: BorderRadius.circular(32),
border: Border.all(color: Colors.white.withValues(alpha: 0.9)),
boxShadow: [
BoxShadow(
color: const Color(0xFF0F172A).withValues(alpha: 0.13),
blurRadius: 34,
offset: const Offset(0, 18),
),
BoxShadow(
color: const Color(0xFF38BDF8).withValues(alpha: 0.1),
blurRadius: 24,
offset: const Offset(0, -6),
),
],
),
child: Row(
children: [
for (var i = 0; i < tabs.length; i++)
Expanded(
child: _GlassNavigationItem(
icon: tabs[i].icon,
label: tabs[i].label,
isSelected: i == currentIndex,
onTap: () => onTap(i),
),
),
],
),
),
),
),
);
}
}
class _GlassNavigationItem extends StatelessWidget {
const _GlassNavigationItem({
required this.icon,
required this.label,
required this.isSelected,
required this.onTap,
});
final IconData icon;
final String label;
final bool isSelected;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
const activeColor = Color(0xFF2563EB);
const inactiveColor = Color(0xFF64748B);
return Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(26),
child: AnimatedContainer(
duration: const Duration(milliseconds: 220),
curve: Curves.easeOutCubic,
alignment: Alignment.center,
margin: const EdgeInsets.symmetric(horizontal: 2),
padding: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
gradient: isSelected
? LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.white.withValues(alpha: 0.95),
activeColor.withValues(alpha: 0.12),
],
)
: null,
color: isSelected ? null : Colors.transparent,
borderRadius: BorderRadius.circular(26),
border: Border.all(
color: isSelected
? Colors.white.withValues(alpha: 0.96)
: Colors.transparent,
),
boxShadow: isSelected
? [
BoxShadow(
color: activeColor.withValues(alpha: 0.16),
blurRadius: 18,
offset: const Offset(0, 8),
),
]
: null,
),
child: AnimatedScale(
duration: const Duration(milliseconds: 180),
curve: Curves.easeOutCubic,
scale: isSelected ? 1 : 0.96,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Icon(
icon,
color: isSelected ? activeColor : inactiveColor,
size: 22,
),
AnimatedSize(
duration: const Duration(milliseconds: 220),
curve: Curves.easeOutCubic,
child: isSelected
? Row(
children: [
const SizedBox(width: 8),
Text(
label,
style: const TextStyle(
color: Color(0xFF2563EB),
fontSize: 13,
fontWeight: FontWeight.w900,
),
),
],
)
: const SizedBox.shrink(),
),
],
),
),
),
),
);
}
}
import 'dart:ui' show ImageFilter;
import 'package:flutter/material.dart';
import 'devices_screen.dart';
import 'timbang_screen.dart';
/// Root scaffold with bottom nav: Devices and Timbang (scale display).
class MainShell extends StatefulWidget {
const MainShell({super.key});
@override
State<MainShell> createState() => _MainShellState();
}
class _MainShellState extends State<MainShell> {
int _index = 0;
static const _tabs = [
(label: 'Devices', icon: Icons.list_alt),
(label: 'Timbang', icon: Icons.monitor_weight),
];
@override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
body: IndexedStack(
index: _index,
children: const [
DevicesScreen(),
TimbangScreen(),
],
),
bottomNavigationBar: _FloatingGlassNavigationBar(
currentIndex: _index,
tabs: _tabs,
onTap: (i) => setState(() => _index = i),
),
);
}
}
class _FloatingGlassNavigationBar extends StatelessWidget {
const _FloatingGlassNavigationBar({
required this.currentIndex,
required this.tabs,
required this.onTap,
});
final int currentIndex;
final List<({String label, IconData icon})> tabs;
final ValueChanged<int> onTap;
@override
Widget build(BuildContext context) {
return SafeArea(
minimum: const EdgeInsets.fromLTRB(20, 0, 20, 18),
child: ClipRRect(
borderRadius: BorderRadius.circular(32),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 24, sigmaY: 24),
child: Container(
height: 72,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.white.withValues(alpha: 0.84),
Colors.white.withValues(alpha: 0.62),
],
),
borderRadius: BorderRadius.circular(32),
border: Border.all(color: Colors.white.withValues(alpha: 0.9)),
boxShadow: [
BoxShadow(
color: const Color(0xFF0F172A).withValues(alpha: 0.13),
blurRadius: 34,
offset: const Offset(0, 18),
),
BoxShadow(
color: const Color(0xFF38BDF8).withValues(alpha: 0.1),
blurRadius: 24,
offset: const Offset(0, -6),
),
],
),
child: Row(
children: [
for (var i = 0; i < tabs.length; i++)
Expanded(
child: _GlassNavigationItem(
icon: tabs[i].icon,
label: tabs[i].label,
isSelected: i == currentIndex,
onTap: () => onTap(i),
),
),
],
),
),
),
),
);
}
}
class _GlassNavigationItem extends StatelessWidget {
const _GlassNavigationItem({
required this.icon,
required this.label,
required this.isSelected,
required this.onTap,
});
final IconData icon;
final String label;
final bool isSelected;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
const activeColor = Color(0xFF2563EB);
const inactiveColor = Color(0xFF64748B);
return Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(26),
child: AnimatedContainer(
duration: const Duration(milliseconds: 220),
curve: Curves.easeOutCubic,
alignment: Alignment.center,
margin: const EdgeInsets.symmetric(horizontal: 2),
padding: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
gradient: isSelected
? LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.white.withValues(alpha: 0.95),
activeColor.withValues(alpha: 0.12),
],
)
: null,
color: isSelected ? null : Colors.transparent,
borderRadius: BorderRadius.circular(26),
border: Border.all(
color: isSelected
? Colors.white.withValues(alpha: 0.96)
: Colors.transparent,
),
boxShadow: isSelected
? [
BoxShadow(
color: activeColor.withValues(alpha: 0.16),
blurRadius: 18,
offset: const Offset(0, 8),
),
]
: null,
),
child: AnimatedScale(
duration: const Duration(milliseconds: 180),
curve: Curves.easeOutCubic,
scale: isSelected ? 1 : 0.96,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Icon(
icon,
color: isSelected ? activeColor : inactiveColor,
size: 22,
),
AnimatedSize(
duration: const Duration(milliseconds: 220),
curve: Curves.easeOutCubic,
child: isSelected
? Row(
children: [
const SizedBox(width: 8),
Text(
label,
style: const TextStyle(
color: Color(0xFF2563EB),
fontSize: 13,
fontWeight: FontWeight.w900,
),
),
],
)
: const SizedBox.shrink(),
),
],
),
),
),
),
);
}
}
File diff suppressed because it is too large. Load diff
+14 -14
View File
@@ -1,14 +1,14 @@
/// Central configuration for SIAB-related constants.
///
/// The [deviceName] can be overridden at build time using:
/// `--dart-define=SIAB_DEVICE_NAME=YourDeviceName`.
class SiabConfig {
const SiabConfig._();
/// Logical Bluetooth name to search for when scanning SIAB devices.
static const String deviceName = String.fromEnvironment(
'SIAB_DEVICE_NAME',
defaultValue: 'SIAB',
);
}
/// Central configuration for SIAB-related constants.
///
/// The [deviceName] can be overridden at build time using:
/// `--dart-define=SIAB_DEVICE_NAME=YourDeviceName`.
class SiabConfig {
const SiabConfig._();
/// Logical Bluetooth name to search for when scanning SIAB devices.
static const String deviceName = String.fromEnvironment(
'SIAB_DEVICE_NAME',
defaultValue: 'SIAB',
);
}
+79 -79
View File
@@ -1,79 +1,79 @@
import 'package:flutter/material.dart';
import '../services/ble_service.dart';
import '../siab_config.dart';
class ConnectionCard extends StatelessWidget {
final BLEService ble;
const ConnectionCard({super.key, required this.ble});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.all(8),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
ble.isConnected
? Icons.bluetooth_connected
: Icons.bluetooth_disabled,
color: ble.isConnected ? Colors.green : Colors.grey,
),
const SizedBox(width: 8),
Text(
ble.isConnected ? 'Connected' : 'Disconnected',
style: Theme.of(context).textTheme.titleLarge,
),
const Spacer(),
if (ble.isScanning || ble.isConnecting)
const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
),
],
),
if (ble.isConnected) ...[
const SizedBox(height: 8),
if (ble.deviceName != null)
Text('Device: ${ble.deviceName}'),
if (ble.deviceAddress != null)
Text(
'Address: ${ble.deviceAddress}',
style: Theme.of(context).textTheme.bodySmall,
),
],
if (!ble.isConnected && !ble.isScanning && !ble.isConnecting) ...[
const SizedBox(height: 8),
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: () async {
final success = await ble.autoConnect();
if (!success && context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'Failed to find ${SiabConfig.deviceName} device',
),
backgroundColor: Colors.orange,
),
);
}
},
icon: const Icon(Icons.search),
label: const Text('Scan & Connect'),
),
),
],
],
),
),
);
}
}
import 'package:flutter/material.dart';
import '../services/ble_service.dart';
import '../siab_config.dart';
class ConnectionCard extends StatelessWidget {
final BLEService ble;
const ConnectionCard({super.key, required this.ble});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.all(8),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
ble.isConnected
? Icons.bluetooth_connected
: Icons.bluetooth_disabled,
color: ble.isConnected ? Colors.green : Colors.grey,
),
const SizedBox(width: 8),
Text(
ble.isConnected ? 'Connected' : 'Disconnected',
style: Theme.of(context).textTheme.titleLarge,
),
const Spacer(),
if (ble.isScanning || ble.isConnecting)
const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
),
],
),
if (ble.isConnected) ...[
const SizedBox(height: 8),
if (ble.deviceName != null)
Text('Device: ${ble.deviceName}'),
if (ble.deviceAddress != null)
Text(
'Address: ${ble.deviceAddress}',
style: Theme.of(context).textTheme.bodySmall,
),
],
if (!ble.isConnected && !ble.isScanning && !ble.isConnecting) ...[
const SizedBox(height: 8),
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: () async {
final success = await ble.autoConnect();
if (!success && context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'Failed to find ${SiabConfig.deviceName} device',
),
backgroundColor: Colors.orange,
),
);
}
},
icon: const Icon(Icons.search),
label: const Text('Scan & Connect'),
),
),
],
],
),
),
);
}
}
+126 -126
View File
@@ -1,126 +1,126 @@
import 'package:flutter/material.dart';
import '../services/ble_service.dart';
class DataPacketCard extends StatelessWidget {
final DataPacket packet;
const DataPacketCard({super.key, required this.packet});
@override
Widget build(BuildContext context) {
final timeStr = '${packet.timestamp.hour.toString().padLeft(2, '0')}:'
'${packet.timestamp.minute.toString().padLeft(2, '0')}:'
'${packet.timestamp.second.toString().padLeft(2, '0')}';
return Card(
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: ExpansionTile(
leading: CircleAvatar(
backgroundColor: Theme.of(context).primaryColor,
child: Text(
'#${packet.packetNumber}',
style: const TextStyle(color: Colors.white, fontSize: 12),
),
),
title: Text(
packet.hexString,
style: const TextStyle(fontFamily: 'monospace', fontSize: 14),
),
subtitle: Text('$timeStr • ${packet.data.length} bytes'),
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSection('Hex', packet.hexString),
const SizedBox(height: 8),
// 'timbang' style: bytes shown in decimal (matching Python output)
_buildSection('timbang', packet.bytesString),
const SizedBox(height: 16),
if (packet.value32BitUnsigned != null) ...[
_buildValueRow(
'32-bit Unsigned (BE)',
packet.value32BitUnsigned.toString(),
),
_buildValueRow(
'32-bit Signed (BE)',
packet.value32BitSigned.toString(),
),
if (packet.value32BitUnsigned! > 0) ...[
_buildValueRow(
'As Float (÷100)',
(packet.value32BitUnsigned! / 100.0).toStringAsFixed(2),
),
_buildValueRow(
'As Float (÷1000)',
(packet.value32BitUnsigned! / 1000.0).toStringAsFixed(3),
),
],
],
if (packet.value16BitUnsigned != null) ...[
const SizedBox(height: 8),
_buildValueRow(
'16-bit Unsigned (BE)',
packet.value16BitUnsigned.toString(),
),
_buildValueRow(
'16-bit Signed (BE)',
packet.value16BitSigned.toString(),
),
],
if (packet.asciiString != null) ...[
const SizedBox(height: 8),
_buildSection('ASCII', packet.asciiString!),
],
],
),
),
],
),
);
}
Widget _buildSection(String label, String value) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12,
color: Colors.grey,
),
),
const SizedBox(height: 4),
SelectableText(
value,
style: const TextStyle(fontFamily: 'monospace', fontSize: 14),
),
],
);
}
Widget _buildValueRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
label,
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
Text(
value,
style: const TextStyle(
fontFamily: 'monospace',
fontWeight: FontWeight.bold,
),
),
],
),
);
}
}
import 'package:flutter/material.dart';
import '../services/ble_service.dart';
class DataPacketCard extends StatelessWidget {
final DataPacket packet;
const DataPacketCard({super.key, required this.packet});
@override
Widget build(BuildContext context) {
final timeStr = '${packet.timestamp.hour.toString().padLeft(2, '0')}:'
'${packet.timestamp.minute.toString().padLeft(2, '0')}:'
'${packet.timestamp.second.toString().padLeft(2, '0')}';
return Card(
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: ExpansionTile(
leading: CircleAvatar(
backgroundColor: Theme.of(context).primaryColor,
child: Text(
'#${packet.packetNumber}',
style: const TextStyle(color: Colors.white, fontSize: 12),
),
),
title: Text(
packet.hexString,
style: const TextStyle(fontFamily: 'monospace', fontSize: 14),
),
subtitle: Text('$timeStr • ${packet.data.length} bytes'),
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSection('Hex', packet.hexString),
const SizedBox(height: 8),
// 'timbang' style: bytes shown in decimal (matching Python output)
_buildSection('timbang', packet.bytesString),
const SizedBox(height: 16),
if (packet.value32BitUnsigned != null) ...[
_buildValueRow(
'32-bit Unsigned (BE)',
packet.value32BitUnsigned.toString(),
),
_buildValueRow(
'32-bit Signed (BE)',
packet.value32BitSigned.toString(),
),
if (packet.value32BitUnsigned! > 0) ...[
_buildValueRow(
'As Float (÷100)',
(packet.value32BitUnsigned! / 100.0).toStringAsFixed(2),
),
_buildValueRow(
'As Float (÷1000)',
(packet.value32BitUnsigned! / 1000.0).toStringAsFixed(3),
),
],
],
if (packet.value16BitUnsigned != null) ...[
const SizedBox(height: 8),
_buildValueRow(
'16-bit Unsigned (BE)',
packet.value16BitUnsigned.toString(),
),
_buildValueRow(
'16-bit Signed (BE)',
packet.value16BitSigned.toString(),
),
],
if (packet.asciiString != null) ...[
const SizedBox(height: 8),
_buildSection('ASCII', packet.asciiString!),
],
],
),
),
],
),
);
}
Widget _buildSection(String label, String value) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12,
color: Colors.grey,
),
),
const SizedBox(height: 4),
SelectableText(
value,
style: const TextStyle(fontFamily: 'monospace', fontSize: 14),
),
],
);
}
Widget _buildValueRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
label,
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
Text(
value,
style: const TextStyle(
fontFamily: 'monospace',
fontWeight: FontWeight.bold,
),
),
],
),
);
}
}
+76 -76
View File
@@ -1,76 +1,76 @@
import 'package:flutter/material.dart';
import '../services/ble_service.dart';
class StatisticsCard extends StatelessWidget {
final BLEService ble;
const StatisticsCard({super.key, required this.ble});
@override
Widget build(BuildContext context) {
final duration = ble.streamingDuration;
final durationStr = duration != null
? '${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}'
: '0:00';
return Card(
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_StatItem(
icon: Icons.data_usage,
label: 'Packets',
value: '${ble.packetCount}',
),
_StatItem(
icon: Icons.speed,
label: 'Rate',
value: '${ble.packetsPerSecond.toStringAsFixed(2)}/s',
),
_StatItem(
icon: Icons.timer,
label: 'Duration',
value: durationStr,
),
],
),
),
);
}
}
class _StatItem extends StatelessWidget {
final IconData icon;
final String label;
final String value;
const _StatItem({
required this.icon,
required this.label,
required this.value,
});
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 24, color: Theme.of(context).primaryColor),
const SizedBox(height: 4),
Text(
value,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
label,
style: Theme.of(context).textTheme.bodySmall,
),
],
);
}
}
import 'package:flutter/material.dart';
import '../services/ble_service.dart';
class StatisticsCard extends StatelessWidget {
final BLEService ble;
const StatisticsCard({super.key, required this.ble});
@override
Widget build(BuildContext context) {
final duration = ble.streamingDuration;
final durationStr = duration != null
? '${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}'
: '0:00';
return Card(
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_StatItem(
icon: Icons.data_usage,
label: 'Packets',
value: '${ble.packetCount}',
),
_StatItem(
icon: Icons.speed,
label: 'Rate',
value: '${ble.packetsPerSecond.toStringAsFixed(2)}/s',
),
_StatItem(
icon: Icons.timer,
label: 'Duration',
value: durationStr,
),
],
),
),
);
}
}
class _StatItem extends StatelessWidget {
final IconData icon;
final String label;
final String value;
const _StatItem({
required this.icon,
required this.label,
required this.value,
});
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 24, color: Theme.of(context).primaryColor),
const SizedBox(height: 4),
Text(
value,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
label,
style: Theme.of(context).textTheme.bodySmall,
),
],
);
}
}
+1 -1
View File
@@ -1 +1 @@
flutter/ephemeral
flutter/ephemeral
+88 -88
View File
@@ -1,88 +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}
)
# 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}
)
+26 -26
View File
@@ -1,26 +1,26 @@
cmake_minimum_required(VERSION 3.13)
project(runner LANGUAGES CXX)
# Define the application target. To change its name, change BINARY_NAME in the
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
# work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME}
"main.cc"
"my_application.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)
# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME})
# Add preprocessor definitions for the application ID.
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
# Add dependency libraries. Add any application-specific dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
cmake_minimum_required(VERSION 3.13)
project(runner LANGUAGES CXX)
# Define the application target. To change its name, change BINARY_NAME in the
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
# work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME}
"main.cc"
"my_application.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)
# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME})
# Add preprocessor definitions for the application ID.
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
# Add dependency libraries. Add any application-specific dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
+6 -6
View File
@@ -1,6 +1,6 @@
#include "my_application.h"
int main(int argc, char** argv) {
g_autoptr(MyApplication) app = my_application_new();
return g_application_run(G_APPLICATION(app), argc, argv);
}
#include "my_application.h"
int main(int argc, char** argv) {
g_autoptr(MyApplication) app = my_application_new();
return g_application_run(G_APPLICATION(app), argc, argv);
}
+18 -18
View File
@@ -1,18 +1,18 @@
#ifndef FLUTTER_MY_APPLICATION_H_
#define FLUTTER_MY_APPLICATION_H_
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
GtkApplication)
/**
* my_application_new:
*
* Creates a new Flutter-based application.
*
* Returns: a new #MyApplication.
*/
MyApplication* my_application_new();
#endif // FLUTTER_MY_APPLICATION_H_
#ifndef FLUTTER_MY_APPLICATION_H_
#define FLUTTER_MY_APPLICATION_H_
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
GtkApplication)
/**
* my_application_new:
*
* Creates a new Flutter-based application.
*
* Returns: a new #MyApplication.
*/
MyApplication* my_application_new();
#endif // FLUTTER_MY_APPLICATION_H_
+7 -7
View File
@@ -1,7 +1,7 @@
# Flutter-related
**/Flutter/ephemeral/
**/Pods/
# Xcode-related
**/dgph
**/xcuserdata/
# Flutter-related
**/Flutter/ephemeral/
**/Pods/
# Xcode-related
**/dgph
**/xcuserdata/
+1 -1
View File
@@ -1 +1 @@
#include "ephemeral/Flutter-Generated.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"
+1 -1
View File
@@ -1 +1 @@
#include "ephemeral/Flutter-Generated.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"
@@ -1,8 +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>
<?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>
@@ -1,99 +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 = "33CC10EC2044A3C60003C045"
BuildableName = "siab_bluetooth_app.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 = "33CC10EC2044A3C60003C045"
BuildableName = "siab_bluetooth_app.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C80D4294CF70F00263BE5"
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 = "33CC10EC2044A3C60003C045"
BuildableName = "siab_bluetooth_app.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 = "33CC10EC2044A3C60003C045"
BuildableName = "siab_bluetooth_app.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?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 = "33CC10EC2044A3C60003C045"
BuildableName = "siab_bluetooth_app.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 = "33CC10EC2044A3C60003C045"
BuildableName = "siab_bluetooth_app.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C80D4294CF70F00263BE5"
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 = "33CC10EC2044A3C60003C045"
BuildableName = "siab_bluetooth_app.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 = "33CC10EC2044A3C60003C045"
BuildableName = "siab_bluetooth_app.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+7 -7
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
@@ -1,8 +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>
<?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>
+13 -13
View File
@@ -1,13 +1,13 @@
import Cocoa
import FlutterMacOS
@main
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
}
import Cocoa
import FlutterMacOS
@main
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
}
@@ -1,68 +1,68 @@
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_1024.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_1024.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Loaded 100 of 125 files, more files were not shown because too many files have changed in this diff. Show more