This commit is contained in:
凉生丶因源 2024-07-09 22:34:59 +08:00
parent b6e6d81abf
commit 30987448a6
235 changed files with 20348 additions and 0 deletions

46
.gitignore vendored Normal file
View File

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

10
.metadata Normal file
View File

@ -0,0 +1,10 @@
# 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: adc687823a831bbebe28bdccfac1a628ca621513
channel: stable
project_type: app

11
android/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties

63
android/app/build.gradle Normal file
View File

@ -0,0 +1,63 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 33
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "org.thingsboard.app"
minSdkVersion 21
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
dependencies {
implementation 'androidx.browser:browser:1.0.0'
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

View File

@ -0,0 +1,30 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.thingsboard.app">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />
</intent>
</queries>
<application android:usesCleartextTraffic="true"/>
</manifest>

View File

@ -0,0 +1,114 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.thingsboard.app">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />
</intent>
</queries>
<application
android:requestLegacyExternalStorage="true"
android:label="ThingsBoard App"
android:networkSecurityConfig="@xml/network_security_config"
android:icon="@mipmap/launcher_icon">
<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
See README(https://goo.gl/l4GJaQ) for more. -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@mipmap/thingsboard"
/>
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!-- App Links -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="demo.thingsboard.io"
android:pathPrefix="/api/noauth/qr" />
</intent-filter>
</activity>
<activity
android:name=".TbWebCallbackActivity"
android:exported="true" >
<intent-filter android:label="tb_web_auth">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="org.thingsboard.app.auth" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2"
/>
<meta-data android:name="io.flutter.network-policy"
android:resource="@xml/network_security_config"/>
<!-- A custom Android Notification Channel to deliver FCM notifications on a non-default channel -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="general" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.flutter_inappwebview.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application>
</manifest>

View File

@ -0,0 +1,16 @@
package org.thingsboard.app
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
class KeepAliveService: Service() {
companion object {
val binder = Binder()
}
override fun onBind(intent: Intent): IBinder {
return binder
}
}

View File

@ -0,0 +1,20 @@
package org.thingsboard.app
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
registerTbWebAuth(flutterEngine)
}
fun registerTbWebAuth(flutterEngine: FlutterEngine) {
val channel = MethodChannel(flutterEngine.dartExecutor, "tb_web_auth")
channel.setMethodCallHandler(TbWebAuthHandler(this))
}
}

View File

@ -0,0 +1,50 @@
package org.thingsboard.app
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
class TbWebAuthHandler(private val context: Context): MethodCallHandler {
companion object {
val callbacks = mutableMapOf<String, Result>()
}
override fun onMethodCall(call: MethodCall, resultCallback: Result) {
when (call.method) {
"authenticate" -> {
val url = Uri.parse(call.argument("url"))
val callbackUrlScheme = call.argument<String>("callbackUrlScheme")!!
val saveHistory = call.argument<Boolean>("saveHistory")
callbacks[callbackUrlScheme] = resultCallback
val intent = CustomTabsIntent.Builder().build()
val keepAliveIntent = Intent(context, KeepAliveService::class.java)
intent.intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
if (saveHistory != null && !saveHistory) {
intent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
}
intent.intent.putExtra("android.support.customtabs.extra.KEEP_ALIVE", keepAliveIntent)
intent.launchUrl(context, url)
}
"cleanUpDanglingCalls" -> {
callbacks.forEach{ (_, danglingResultCallback) ->
danglingResultCallback.error("CANCELED", "User canceled login", null)
}
callbacks.clear()
resultCallback.success(null)
}
else -> resultCallback.notImplemented()
}
}
}

View File

@ -0,0 +1,20 @@
package org.thingsboard.app
import android.app.Activity
import android.net.Uri
import android.os.Bundle
class TbWebCallbackActivity: Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val url = intent?.data
val scheme = url?.scheme
if (scheme != null) {
TbWebAuthHandler.callbacks.remove(scheme)?.success(url.toString())
}
finish()
}
}

View File

@ -0,0 +1,11 @@
<?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/thingsboard" />
</item>
</layer-list>

View File

@ -0,0 +1,11 @@
<?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/thingsboard" />
</item>
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

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

View File

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

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external_files"
path="." />
</paths>

View File

@ -0,0 +1,29 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.thingsboard.app">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />
</intent>
</queries>
</manifest>

31
android/build.gradle Normal file
View File

@ -0,0 +1,31 @@
buildscript {
ext.kotlin_version = '1.7.10'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

View File

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true

View File

@ -0,0 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip

11
android/settings.gradle Normal file
View File

@ -0,0 +1,11 @@
include ':app'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

View File

@ -0,0 +1 @@
include ':app'

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 256 315" xmlns="http://www.w3.org/2000/svg">
<path d="M213.803394,167.030943 C214.2452,214.609646 255.542482,230.442639 256,230.644727 C255.650812,231.761357 249.401383,253.208293 234.24263,275.361446 C221.138555,294.513969 207.538253,313.596333 186.113759,313.991545 C165.062051,314.379442 158.292752,301.507828 134.22469,301.507828 C110.163898,301.507828 102.642899,313.596301 82.7151126,314.379442 C62.0350407,315.16201 46.2873831,293.668525 33.0744079,274.586162 C6.07529317,235.552544 -14.5576169,164.286328 13.147166,116.18047 C26.9103111,92.2909053 51.5060917,77.1630356 78.2026125,76.7751096 C98.5099145,76.3877456 117.677594,90.4371851 130.091705,90.4371851 C142.497945,90.4371851 165.790755,73.5415029 190.277627,76.0228474 C200.528668,76.4495055 229.303509,80.1636878 247.780625,107.209389 C246.291825,108.132333 213.44635,127.253405 213.803394,167.030988 M174.239142,50.1987033 C185.218331,36.9088319 192.607958,18.4081019 190.591988,0 C174.766312,0.636050225 155.629514,10.5457909 144.278109,23.8283506 C134.10507,35.5906758 125.195775,54.4170275 127.599657,72.4607932 C145.239231,73.8255433 163.259413,63.4970262 174.239142,50.1987249" fill="#000000"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,37 @@
<svg width="156" height="106" viewBox="0 0 156 106" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="156" height="106" fill="white"/>
<path d="M17 71C17 70.4477 17.4477 70 18 70H26C26.5523 70 27 70.4477 27 71V89C27 89.5523 26.5523 90 26 90H18C17.4477 90 17 89.5523 17 89V71Z" fill="#808080" fill-opacity="0.1"/>
<path d="M17 79C17 78.4477 17.4477 78 18 78H26C26.5523 78 27 78.4477 27 79V89C27 89.5523 26.5523 90 26 90H18C17.4477 90 17 89.5523 17 89V79Z" fill="#808080" fill-opacity="0.5"/>
<path d="M45 71C45 70.4477 45.4477 70 46 70H54C54.5523 70 55 70.4477 55 71V89C55 89.5523 54.5523 90 54 90H46C45.4477 90 45 89.5523 45 89V71Z" fill="#808080" fill-opacity="0.1"/>
<path d="M59 71C59 70.4477 59.4477 70 60 70H68C68.5523 70 69 70.4477 69 71V89C69 89.5523 68.5523 90 68 90H60C59.4477 90 59 89.5523 59 89V71Z" fill="#808080" fill-opacity="0.1"/>
<path d="M73 71C73 70.4477 73.4477 70 74 70H82C82.5523 70 83 70.4477 83 71V89C83 89.5523 82.5523 90 82 90H74C73.4477 90 73 89.5523 73 89V71Z" fill="#808080" fill-opacity="0.1"/>
<path d="M87 71C87 70.4477 87.4477 70 88 70H96C96.5523 70 97 70.4477 97 71V89C97 89.5523 96.5523 90 96 90H88C87.4477 90 87 89.5523 87 89V71Z" fill="#808080" fill-opacity="0.1"/>
<path d="M101 71C101 70.4477 101.448 70 102 70H110C110.552 70 111 70.4477 111 71V89C111 89.5523 110.552 90 110 90H102C101.448 90 101 89.5523 101 89V71Z" fill="#808080" fill-opacity="0.1"/>
<path d="M115 71C115 70.4477 115.448 70 116 70H124C124.552 70 125 70.4477 125 71V89C125 89.5523 124.552 90 124 90H116C115.448 90 115 89.5523 115 89V71Z" fill="#808080" fill-opacity="0.1"/>
<path d="M129 71C129 70.4477 129.448 70 130 70H138C138.552 70 139 70.4477 139 71V89C139 89.5523 138.552 90 138 90H130C129.448 90 129 89.5523 129 89V71Z" fill="#808080" fill-opacity="0.1"/>
<path d="M31 71C31 70.4477 31.4477 70 32 70H40C40.5523 70 41 70.4477 41 71V89C41 89.5523 40.5523 90 40 90H32C31.4477 90 31 89.5523 31 89V71Z" fill="#808080" fill-opacity="0.1"/>
<path d="M31 84C31 83.4477 31.4477 83 32 83H40C40.5523 83 41 83.4477 41 84V89C41 89.5523 40.5523 90 40 90H32C31.4477 90 31 89.5523 31 89V84Z" fill="#808080" fill-opacity="0.5"/>
<path d="M45 86C45 85.4477 45.4477 85 46 85H54C54.5523 85 55 85.4477 55 86V89C55 89.5523 54.5523 90 54 90H46C45.4477 90 45 89.5523 45 89V86Z" fill="#808080" fill-opacity="0.5"/>
<path d="M59 82C59 81.4477 59.4477 81 60 81H68C68.5523 81 69 81.4477 69 82V89C69 89.5523 68.5523 90 68 90H60C59.4477 90 59 89.5523 59 89V82Z" fill="#808080" fill-opacity="0.5"/>
<path d="M73 75C73 74.4477 73.4477 74 74 74H82C82.5523 74 83 74.4477 83 75V89C83 89.5523 82.5523 90 82 90H74C73.4477 90 73 89.5523 73 89V75Z" fill="#808080" fill-opacity="0.5"/>
<path d="M87 78C87 77.4477 87.4477 77 88 77H96C96.5523 77 97 77.4477 97 78V89C97 89.5523 96.5523 90 96 90H88C87.4477 90 87 89.5523 87 89V78Z" fill="#808080" fill-opacity="0.5"/>
<path d="M101 83C101 82.4477 101.448 82 102 82H110C110.552 82 111 82.4477 111 83V89C111 89.5523 110.552 90 110 90H102C101.448 90 101 89.5523 101 89V83Z" fill="#808080" fill-opacity="0.5"/>
<path d="M115 75C115 74.4477 115.448 74 116 74H124C124.552 74 125 74.4477 125 75V89C125 89.5523 124.552 90 124 90H116C115.448 90 115 89.5523 115 89V75Z" fill="#808080" fill-opacity="0.5"/>
<path d="M129 79C129 78.4477 129.448 78 130 78H138C138.552 78 139 78.4477 139 79V89C139 89.5523 138.552 90 138 90H130C129.448 90 129 89.5523 129 89V79Z" fill="#808080" fill-opacity="0.5"/>
<path d="M40 16C43.6606 16 47.2727 16.8373 50.5599 18.448L46.3354 27.0698C44.3632 26.1035 42.1962 25.6012 40 25.6012L40 16Z" fill="#808080" fill-opacity="0.38"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M39 26.6011L39 14.9999L40 14.9999C43.8131 14.9999 47.5757 15.8721 50.9999 17.5498L51.8978 17.9898L46.7934 28.4077L45.8954 27.9677C44.0602 27.0685 42.0436 26.6011 40 26.6011L39 26.6011ZM41 24.6336C42.6715 24.7423 44.3142 25.1231 45.8631 25.7609L49.2123 18.9254C46.6156 17.7903 43.8313 17.1448 41 17.0216L41 24.6336Z" fill="white"/>
<path d="M63.7911 36.842C63.2701 32.9173 61.7862 29.1823 59.4717 25.9701C57.1572 22.7579 54.084 20.1681 50.5259 18.4317L46.3149 27.0602C48.4496 28.1019 50.2934 29.6557 51.682 31.5828C53.0706 33.51 53.9608 35.7508 54.2734 38.1055L63.7911 36.842Z" fill="#808080" fill-opacity="0.5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M44.978 27.5199L50.0662 17.0941L50.9648 17.5327C54.6712 19.3415 57.8725 22.0391 60.2834 25.3852C62.6944 28.7313 64.2401 32.6218 64.7828 36.7101L64.9144 37.7014L53.4141 39.228L53.2825 38.2367C52.9916 36.0456 52.1632 33.9604 50.871 32.1671C49.5789 30.3738 47.8631 28.9279 45.8767 27.9585L44.978 27.5199ZM47.6383 26.6289C49.5472 27.7194 51.204 29.208 52.4937 30.9979C53.7834 32.7878 54.6711 34.8306 55.1013 36.9865L62.647 35.9849C62.0445 32.586 60.6837 29.3619 58.6608 26.5544C56.6379 23.7469 54.0102 21.4355 50.9768 19.7882L47.6383 26.6289Z" fill="white"/>
<path d="M18.168 49.9682C20.5617 55.2109 24.7622 59.4172 30.0016 61.8182C35.241 64.2192 41.1695 64.6546 46.7034 63.0448C52.2374 61.435 57.0073 57.8876 60.1413 53.0508C63.2753 48.2141 64.5642 42.4111 63.7723 36.7024L54.2622 38.0216C54.7373 41.4465 53.964 44.928 52.0838 47.8299C50.2035 50.7317 47.3418 52.8599 44.0217 53.8257C40.7016 54.7915 37.1448 54.5303 34.0014 53.0898C30.858 51.6493 28.338 49.1258 26.9018 45.9804L18.168 49.9682Z" fill="#808080" fill-opacity="0.26"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.8433 49.4739L27.3965 44.6554L27.8118 45.5651C29.1482 48.492 31.4932 50.8403 34.4183 52.1807C37.3434 53.5212 40.6532 53.7642 43.7427 52.8655C46.8322 51.9668 49.4952 49.9863 51.2448 47.2861C52.9945 44.5858 53.7141 41.3461 53.272 38.159L53.1346 37.1685L64.6257 35.5745L64.7631 36.565C65.588 42.5115 64.2454 48.5564 60.9808 53.5946C57.7162 58.6329 52.7476 62.3281 46.983 64.005C41.2185 65.6818 35.043 65.2283 29.5853 62.7273C24.1276 60.2262 19.7521 55.8447 17.2586 50.3836L16.8433 49.4739ZM19.513 50.4535C21.8626 55.0585 25.7011 58.7473 30.4185 60.9091C35.4396 63.21 41.121 63.6273 46.4244 62.0846C51.7278 60.5419 56.2989 57.1423 59.3024 52.5071C62.1242 48.1522 63.3851 42.98 62.898 37.8333L55.3582 38.8792C55.6018 42.2155 54.7522 45.551 52.9233 48.3736C50.9124 51.477 47.852 53.7531 44.3013 54.7859C40.7506 55.8188 36.9468 55.5394 33.5851 53.9989C30.5275 52.5977 28.0214 50.2384 26.4374 47.2919L19.513 50.4535Z" fill="white"/>
<path d="M18.2184 50.0776C15.7815 44.8106 15.3356 38.8389 16.9634 33.2683C18.5912 27.6978 22.1823 22.9057 27.0718 19.7795L32.2437 27.8687C29.3103 29.7442 27.1558 32.6192 26.1792 35.9613C25.2026 39.3033 25.4701 42.886 26.9321 46.046L18.2184 50.0776Z" fill="#808080" fill-opacity="0.35"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.7258 48.7412L25.6341 45.5449C24.4203 42.4003 24.2687 38.934 25.2193 35.681C26.1699 32.4279 28.164 29.5886 30.88 27.5924L26.7797 21.1792C22.518 24.1726 19.3895 28.5312 17.9232 33.549C16.457 38.5667 16.7464 43.9241 18.7258 48.7412ZM17.3108 50.4977C14.7724 45.0112 14.3079 38.7907 16.0035 32.988C17.6991 27.1854 21.4399 22.1936 26.5331 18.9372L27.3757 18.3985L33.6249 28.1727L32.7824 28.7113C30.0527 30.4567 28.0478 33.132 27.139 36.2419C26.2303 39.3519 26.4792 42.6858 27.8397 45.6263L28.2596 46.5339L17.7307 51.4053L17.3108 50.4977Z" fill="white"/>
<path d="M39.9999 16.0002C35.3266 16.0002 30.755 17.3645 26.8462 19.9258L32.1083 27.9565C34.4534 26.4199 37.1962 25.6014 39.9999 25.6014L39.9999 16.0002Z" fill="#808080" fill-opacity="0.1"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.4619 19.6372L26.2983 19.0891C30.3701 16.4212 35.1321 14.9999 40.0001 14.9999L41.0001 14.9999L41.0001 26.6011L40.0001 26.6011C37.3911 26.6011 34.8389 27.3628 32.6566 28.7927L31.8202 29.3408L25.4619 19.6372ZM32.4147 26.599C34.4337 25.4562 36.6851 24.7843 39.0001 24.6336L39.0001 17.0217C35.2044 17.1868 31.5082 18.2899 28.2428 20.2321L32.4147 26.599Z" fill="white"/>
<path d="M73 16H139V28H73V16Z" fill="#CFCFCF" fill-opacity="0.1"/>
<path d="M73 16H133V28H73V16Z" fill="#808080" fill-opacity="0.1"/>
<path d="M73 33H139V45H73V33Z" fill="#CFCFCF" fill-opacity="0.1"/>
<path d="M73 33H115V45H73V33Z" fill="#808080" fill-opacity="0.23"/>
<path d="M73 50H139V62H73V50Z" fill="#CFCFCF" fill-opacity="0.1"/>
<path d="M73 50H86V62H73V50Z" fill="#808080" fill-opacity="0.44"/>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -0,0 +1,14 @@
<svg width="156" height="74" viewBox="0 0 156 74" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="156" height="74" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M104 27H45V54V58V60H83V58H104V27Z" fill="#808080" fill-opacity="0.1"/>
<path d="M61 31H49V39H61V31Z" fill="#808080" fill-opacity="0.5"/>
<path d="M61 43H49V47H61V43Z" fill="#808080" fill-opacity="0.5"/>
<path d="M77 31H65V35H77V31Z" fill="#808080" fill-opacity="0.5"/>
<path d="M77 39H65V47H77V39Z" fill="#808080" fill-opacity="0.5"/>
<path d="M100 31H81V47H100V31Z" fill="#808080" fill-opacity="0.5"/>
<path d="M106 16V14C108.917 14 111.715 15.1589 113.778 17.2218C115.841 19.2847 117 22.0826 117 25H115C115 22.6131 114.052 20.3239 112.364 18.636C110.676 16.9482 108.387 16 106 16Z" fill="#808080" fill-opacity="0.2"/>
<path d="M106 25V22C106.796 22 107.559 22.3161 108.121 22.8787C108.684 23.4413 109 24.2044 109 25H106Z" fill="#808080" fill-opacity="0.2"/>
<path d="M106 20V18C107.857 18 109.637 18.7375 110.95 20.0503C112.263 21.363 113 23.1435 113 25H111C111 23.6739 110.473 22.4021 109.536 21.4645C108.598 20.5268 107.326 20 106 20Z" fill="#808080" fill-opacity="0.2"/>
<path d="M43 27H39V34H41V58H43V27Z" fill="#808080" fill-opacity="0.2"/>
<path d="M79 56H49V51H100V54H79V56Z" fill="#808080" fill-opacity="0.2"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 263 263" xmlns="http://www.w3.org/2000/svg">
<path d="M263 131.5C263 58.9 204.1 0 131.5 0S0 58.9 0 131.5c0 65.6 48.1 120 110.9 129.9v-91.9H77.5v-38h33.4v-29c0-33 19.6-51.2 49.7-51.2 14.4 0 29.4 2.6 29.4 2.6v32.4h-16.5c-16.3 0-21.4 10.1-21.4 20.5v24.7h36.4l-5.8 38h-30.6v91.9c62.8-9.9 110.9-64.3 110.9-129.9z" fill="#1877f2"/>
<path d="M182.7 169.5l5.8-38H152v-24.7c0-10.4 5.1-20.5 21.4-20.5H190V53.9s-15-2.6-29.4-2.6c-30 0-49.7 18.2-49.7 51.2v29H77.5v38h33.4v91.9c6.7 1.1 13.6 1.6 20.5 1.6s13.9-.5 20.5-1.6v-91.9h30.8z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 606 B

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 32.7 32.7" xmlns="http://www.w3.org/2000/svg">
<path d="M16.3 0C7.3 0 0 7.3 0 16.3c0 7.2 4.7 13.3 11.1 15.5.8.1 1.1-.4 1.1-.8v-2.8c-4.5 1-5.5-2.2-5.5-2.2-.7-1.9-1.8-2.4-1.8-2.4-1.5-1 .1-1 .1-1 1.6.1 2.5 1.7 2.5 1.7 1.5 2.5 3.8 1.8 4.7 1.4.1-1.1.6-1.8 1-2.2-3.6-.4-7.4-1.8-7.4-8.1 0-1.8.6-3.2 1.7-4.4-.2-.4-.7-2.1.2-4.3 0 0 1.4-.4 4.5 1.7 1.3-.4 2.7-.5 4.1-.5s2.8.2 4.1.5c3.1-2.1 4.5-1.7 4.5-1.7.9 2.2.3 3.9.2 4.3 1 1.1 1.7 2.6 1.7 4.4 0 6.3-3.8 7.6-7.4 8 .6.5 1.1 1.5 1.1 3v4.5c0 .4.3.9 1.1.8 6.5-2.2 11.1-8.3 11.1-15.5C32.6 7.3 25.3 0 16.3 0z" fill="#211c19"/>
</svg>

After

Width:  |  Height:  |  Size: 630 B

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
<path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"/>
<path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"/>
<path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"/>
<path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"/>
<path fill="none" d="M0 0h48v48H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 800 B

View File

@ -0,0 +1,10 @@
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_4989_125988)">
<path d="M10 6.5V9.5H7V6.5H10ZM11.5 5H5.5V11H11.5V5ZM10 14.5V17.5H7V14.5H10ZM11.5 13H5.5V19H11.5V13ZM18 6.5V9.5H15V6.5H18ZM19.5 5H13.5V11H19.5V5ZM13.5 13H15V14.5H13.5V13ZM15 14.5H16.5V16H15V14.5ZM16.5 13H18V14.5H16.5V13ZM13.5 16H15V17.5H13.5V16ZM15 17.5H16.5V19H15V17.5ZM16.5 16H18V17.5H16.5V16ZM18 14.5H19.5V16H18V14.5ZM18 17.5H19.5V19H18V17.5ZM22.5 7H20.5V4H17.5V2H22.5V7ZM22.5 22V17H20.5V20H17.5V22H22.5ZM2.5 22H7.5V20H4.5V17H2.5V22ZM2.5 2V7H4.5V4H7.5V2H2.5Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_4989_125988">
<rect width="24" height="24" fill="white" transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 758 B

View File

@ -0,0 +1,11 @@
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5018_125009)">
<path d="M22.25 7H20.25V4H17.25V2H22.25V7ZM22.25 22V17H20.25V20H17.25V22H22.25ZM2.25 22H7.25V20H4.25V17H2.25V22ZM2.25 2V7H4.25V4H7.25V2H2.25Z" fill="black"/>
<path d="M9.7373 14.0527L11.6074 15.5371L10.8115 16.2354L8.97559 14.7656L9.7373 14.0527ZM11.6221 11.25V11.6406C11.6221 12.1777 11.5521 12.6595 11.4121 13.0859C11.2721 13.5124 11.0719 13.8753 10.8115 14.1748C10.5511 14.4743 10.2402 14.7038 9.87891 14.8633C9.51758 15.0195 9.11719 15.0977 8.67773 15.0977C8.24154 15.0977 7.84277 15.0195 7.48145 14.8633C7.12337 14.7038 6.8125 14.4743 6.54883 14.1748C6.28516 13.8753 6.08008 13.5124 5.93359 13.0859C5.79036 12.6595 5.71875 12.1777 5.71875 11.6406V11.25C5.71875 10.7129 5.79036 10.2327 5.93359 9.80957C6.07682 9.38314 6.27865 9.02018 6.53906 8.7207C6.80273 8.41797 7.11361 8.18848 7.47168 8.03223C7.83301 7.87272 8.23177 7.79297 8.66797 7.79297C9.10742 7.79297 9.50781 7.87272 9.86914 8.03223C10.2337 8.18848 10.5462 8.41797 10.8066 8.7207C11.0671 9.02018 11.2673 9.38314 11.4072 9.80957C11.5505 10.2327 11.6221 10.7129 11.6221 11.25ZM10.3916 11.6406V11.2402C10.3916 10.8431 10.3525 10.4932 10.2744 10.1904C10.1995 9.88444 10.0872 9.62891 9.9375 9.42383C9.79102 9.21549 9.61035 9.05924 9.39551 8.95508C9.18392 8.84766 8.94141 8.79395 8.66797 8.79395C8.40104 8.79395 8.16178 8.84766 7.9502 8.95508C7.73861 9.05924 7.55794 9.21549 7.4082 9.42383C7.25846 9.62891 7.14453 9.88444 7.06641 10.1904C6.98828 10.4932 6.94922 10.8431 6.94922 11.2402V11.6406C6.94922 12.0378 6.98828 12.3893 7.06641 12.6953C7.14453 13.0013 7.25846 13.2601 7.4082 13.4717C7.5612 13.68 7.74349 13.8379 7.95508 13.9453C8.16992 14.0495 8.41081 14.1016 8.67773 14.1016C8.95117 14.1016 9.19368 14.0495 9.40527 13.9453C9.61686 13.8379 9.7959 13.68 9.94238 13.4717C10.0889 13.2601 10.1995 13.0013 10.2744 12.6953C10.3525 12.3893 10.3916 12.0378 10.3916 11.6406ZM12.8672 7.89062H15.3818C15.9222 7.89062 16.3828 7.97201 16.7637 8.13477C17.1445 8.29753 17.4359 8.53841 17.6377 8.85742C17.8428 9.17318 17.9453 9.5638 17.9453 10.0293C17.9453 10.3841 17.8802 10.6966 17.75 10.9668C17.6198 11.237 17.4359 11.4648 17.1982 11.6504C16.9606 11.8327 16.6774 11.9743 16.3486 12.0752L15.9775 12.2559H13.7168L13.707 11.2842H15.4014C15.6943 11.2842 15.9385 11.2321 16.1338 11.1279C16.3291 11.0238 16.4756 10.8822 16.5732 10.7031C16.6742 10.5208 16.7246 10.3158 16.7246 10.0879C16.7246 9.84049 16.6758 9.62565 16.5781 9.44336C16.4837 9.25781 16.3372 9.11621 16.1387 9.01855C15.9401 8.91764 15.6878 8.86719 15.3818 8.86719H14.0928V15H12.8672V7.89062ZM16.9248 15L15.2549 11.8066L16.5391 11.8018L18.2334 14.9365V15H16.9248Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_5018_125009">
<rect width="24" height="24" fill="white" transform="translate(0.25)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="320" height="320" version="1.1" viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg">
<g stroke-width="28"></g>
<g shape-rendering="auto">
<path d="m151.13 0.00104c-28.363 0-54.915 7.9153-77.613 21.537-6.4723-5.2623-14.605-8.1915-23.067-8.1937a8.7661 8.7661 0 0 0-0.0035 0c-20.154 7.3e-4 -36.679 16.528-36.678 36.682a8.7661 8.7661 0 0 0 0 0.0106c0.0099 8.4147 2.9267 16.483 8.1033 22.927-13.825 22.819-21.865 49.572-21.865 78.161a8.7661 8.7661 0 1 0 17.531 0c0-24.702 6.7193-47.748 18.378-67.574 4.5663 1.9846 9.4727 3.1496 14.519 3.1573a8.7661 8.7661 0 0 0 0.01241 0c20.155 6.2e-4 36.683-16.527 36.682-36.682a8.7661 8.7661 0 0 0 0-4e-3c-0.0016-4.9994-1.1387-9.8628-3.0828-14.397 19.717-11.484 42.585-18.095 67.085-18.095a8.7661 8.7661 0 1 0 0-17.531zm-100.69 30.874c5.9129 2e-3 11.191 2.5121 14.836 7.0769a8.7661 8.7661 0 0 0 0.1826 0.21451c2.6715 3.3798 4.1326 7.5531 4.1341 11.863-0.0015 10.677-8.468 19.144-19.144 19.148-4.37-8e-3 -8.6011-1.5088-12-4.2546a8.7661 8.7661 0 0 0-0.01241-9e-3c-4.514-3.6331-7.1358-9.0979-7.1442-14.893 0.0025-10.677 8.4701-19.144 19.148-19.146z" color="#000000" color-rendering="auto" image-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/>
<path d="m66.992 102.83c-1.492 1.5583-2.3663 3.7103-2.2576 6.0713 0.0962 2.0447 0.91322 4.0204 2.3372 5.5177 6.8051 6.8559 20.223 20.223 20.223 20.223l11.844-11.83s-12.973-12.961-20.176-20.171c-1.604-1.6325-3.7498-2.3141-6.012-2.3243-2.3583-0.0112-4.4673 0.95389-5.9592 2.5122zm32.147 19.983-36.639 36.639c-3.9751 3.976-3.9751 10.421 0 14.397l80.387 80.387c3.9758 3.9759 10.422 3.9763 14.398 0l99.345-99.345c3.9754-3.9764 3.975-10.422-6.7e-4 -14.398l-18.63-18.628-61.758-61.758c-3.976-3.9751-10.421-3.9751-14.397 0l-24.791 24.791zm37.914-37.914s-12.973-12.961-20.176-20.171c-1.604-1.6325-3.7498-2.3141-6.012-2.3243-4.7166-0.0226-8.4341 3.8616-8.2169 8.5834 0.0962 2.0447 0.91322 4.0204 2.3372 5.5177 6.8051 6.8559 20.223 20.223 20.223 20.223zm69.193 5.2132s12.961-12.973 20.171-20.176c1.6325-1.604 2.3141-3.7498 2.3243-6.012 0.0225-4.7166-3.8616-8.4341-8.5834-8.2169-2.0447 0.0962-4.0204 0.91322-5.5177 2.3372-6.8559 6.8051-20.223 20.223-20.223 20.223zm31.753 31.753s12.961-12.973 20.171-20.176c1.6325-1.604 2.314-3.7498 2.3243-6.012 0.0225-4.7166-3.8616-8.4341-8.5834-8.2169-2.0447 0.0962-4.0204 0.91323-5.5177 2.3372-6.8559 6.8051-20.223 20.223-20.223 20.223zm-18.009 69.667s12.973 12.961 20.178 20.169c1.604 1.6324 3.7498 2.314 6.012 2.3243 4.7166 0.0225 8.4342-3.8615 8.2169-8.5834l-2e-3 2e-3c-0.0962-2.0447-0.91415-4.0214-2.3382-5.5186-6.8051-6.8559-20.222-20.222-20.222-20.222l-11.844 11.83zm-37.914 37.914s12.973 12.961 20.178 20.169c1.604 1.6324 3.7498 2.314 6.012 2.3242 4.7166 0.023 8.4342-3.8615 8.2169-8.5834h-2e-3c-0.0962-2.0447-0.91323-4.0205-2.3372-5.5177-6.8051-6.8559-20.223-20.223-20.223-20.223l-11.844 11.83zm-69.667-5.6871s-12.961 12.973-20.169 20.178c-1.6324 1.604-2.314 3.7498-2.3243 6.012-0.02251 4.7166 3.8615 8.4342 8.5834 8.2169h-0.0019c2.0447-0.096 4.0204-0.9132 5.5177-2.3373 6.8561-6.8048 20.223-20.223 20.223-20.223zm-31.753-31.753s-12.961 12.973-20.169 20.178c-1.6324 1.604-2.314 3.7498-2.3243 6.012-0.02251 4.7167 3.8615 8.4342 8.5834 8.2169h-0.0019c2.0447-0.0962 4.0204-0.91322 5.5177-2.3372 6.8561-6.8047 20.223-20.223 20.223-20.223zm87.237-90.554c1.6794-1.7064 3.9669-2.6599 6.2971-2.626 1.6628 0.0237 3.253 0.55012 4.5625 1.5097l16.499 12.1c3.2009 2.297 4.1445 6.6589 2.2308 10.312-1.9137 3.6528-6.1234 5.5243-9.9506 4.4227l6.124 23.948c1.1128 4.3517-1.564 8.9677-5.9833 10.317l-44.642 13.631 8.2456 31.883c1.1728 4.3696-1.5017 9.0445-5.9546 10.407-4.4529 1.3625-8.9756-1.1106-10.068-5.5047l-10.282-39.769c-1.1265-4.3556 1.5493-8.9847 5.9759-10.338l44.661-13.637-4.1219-16.118c-2.7634 3.0643-7.2335 3.8084-10.586 1.7615-3.3531-2.0469-4.6144-6.2896-2.9861-10.047l8.1169-19.454c0.43322-1.0376 1.0673-1.9888 1.8624-2.7973z" color="#000000" color-rendering="auto" fill-rule="evenodd" image-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/>
<path d="m168.87 320c28.363 0 54.915-7.9155 77.614-21.538 6.4724 5.2624 14.605 8.1917 23.067 8.1939a8.7662 8.7662 0 0 0 4e-3 0c20.155-7e-4 36.68-16.528 36.679-36.682a8.7662 8.7662 0 0 0 0-0.011c-0.01-8.4149-2.9267-16.484-8.1034-22.927 13.825-22.82 21.866-49.572 21.866-78.162a8.7662 8.7662 0 1 0-17.531 0c0 24.703-6.7194 47.749-18.378 67.575-4.5664-1.9846-9.4728-3.1496-14.519-3.1573a8.7662 8.7662 0 0 0-0.0124 0c-20.155-6.2e-4 -36.683 16.527-36.682 36.682 2e-3 4.9994 1.1387 9.8628 3.0829 14.397-19.717 11.484-42.586 18.095-67.086 18.095a8.7662 8.7662 0 1 0 0 17.531zm100.69-30.875c-5.913 0-11.191-2.5122-14.836-7.0769a8.7662 8.7662 0 0 0-0.18261-0.2146c-2.6715-3.3799-4.1327-7.5531-4.1341-11.863 2e-3 -10.677 8.4681-19.144 19.144-19.148 4.37 8e-3 8.6012 1.5088 12 4.2547a8.7662 8.7662 0 0 0 0.0124 9e-3c4.5141 3.6332 7.1359 9.098 7.1443 14.893-3e-3 10.677-8.4702 19.145-19.148 19.146z" color="#000000" color-rendering="auto" image-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="320" height="320" version="1.1" viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg">
<g stroke-width="28"></g>
<g shape-rendering="auto">
<path d="m66.992 102.83c-1.492 1.5583-2.3663 3.7103-2.2576 6.0713 0.0962 2.0447 0.91322 4.0204 2.3372 5.5177 6.8051 6.8559 20.223 20.223 20.223 20.223l11.844-11.83s-12.973-12.961-20.176-20.171c-1.604-1.6325-3.7498-2.3141-6.012-2.3243-2.3583-0.0112-4.4673 0.95389-5.9592 2.5122zm32.147 19.983-36.639 36.639c-3.9751 3.976-3.9751 10.421 0 14.397l80.387 80.387c3.9758 3.9759 10.422 3.9763 14.398 0l99.345-99.345c3.9754-3.9764 3.975-10.422-6.7e-4 -14.398l-18.63-18.628-61.758-61.758c-3.976-3.9751-10.421-3.9751-14.397 0l-24.791 24.791zm37.914-37.914s-12.973-12.961-20.176-20.171c-1.604-1.6325-3.7498-2.3141-6.012-2.3243-4.7166-0.0226-8.4341 3.8616-8.2169 8.5834 0.0962 2.0447 0.91322 4.0204 2.3372 5.5177 6.8051 6.8559 20.223 20.223 20.223 20.223zm69.193 5.2132s12.961-12.973 20.171-20.176c1.6325-1.604 2.3141-3.7498 2.3243-6.012 0.0225-4.7166-3.8616-8.4341-8.5834-8.2169-2.0447 0.0962-4.0204 0.91322-5.5177 2.3372-6.8559 6.8051-20.223 20.223-20.223 20.223zm31.753 31.753s12.961-12.973 20.171-20.176c1.6325-1.604 2.314-3.7498 2.3243-6.012 0.0225-4.7166-3.8616-8.4341-8.5834-8.2169-2.0447 0.0962-4.0204 0.91323-5.5177 2.3372-6.8559 6.8051-20.223 20.223-20.223 20.223zm-18.009 69.667s12.973 12.961 20.178 20.169c1.604 1.6324 3.7498 2.314 6.012 2.3243 4.7166 0.0225 8.4342-3.8615 8.2169-8.5834l-2e-3 2e-3c-0.0962-2.0447-0.91415-4.0214-2.3382-5.5186-6.8051-6.8559-20.222-20.222-20.222-20.222l-11.844 11.83zm-37.914 37.914s12.973 12.961 20.178 20.169c1.604 1.6324 3.7498 2.314 6.012 2.3242 4.7166 0.023 8.4342-3.8615 8.2169-8.5834h-2e-3c-0.0962-2.0447-0.91323-4.0205-2.3372-5.5177-6.8051-6.8559-20.223-20.223-20.223-20.223l-11.844 11.83zm-69.667-5.6871s-12.961 12.973-20.169 20.178c-1.6324 1.604-2.314 3.7498-2.3243 6.012-0.02251 4.7166 3.8615 8.4342 8.5834 8.2169h-0.0019c2.0447-0.096 4.0204-0.9132 5.5177-2.3373 6.8561-6.8048 20.223-20.223 20.223-20.223zm-31.753-31.753s-12.961 12.973-20.169 20.178c-1.6324 1.604-2.314 3.7498-2.3243 6.012-0.02251 4.7167 3.8615 8.4342 8.5834 8.2169h-0.0019c2.0447-0.0962 4.0204-0.91322 5.5177-2.3372 6.8561-6.8047 20.223-20.223 20.223-20.223zm87.237-90.554c1.6794-1.7064 3.9669-2.6599 6.2971-2.626 1.6628 0.0237 3.253 0.55012 4.5625 1.5097l16.499 12.1c3.2009 2.297 4.1445 6.6589 2.2308 10.312-1.9137 3.6528-6.1234 5.5243-9.9506 4.4227l6.124 23.948c1.1128 4.3517-1.564 8.9677-5.9833 10.317l-44.642 13.631 8.2456 31.883c1.1728 4.3696-1.5017 9.0445-5.9546 10.407-4.4529 1.3625-8.9756-1.1106-10.068-5.5047l-10.282-39.769c-1.1265-4.3556 1.5493-8.9847 5.9759-10.338l44.661-13.637-4.1219-16.118c-2.7634 3.0643-7.2335 3.8084-10.586 1.7615-3.3531-2.0469-4.6144-6.2896-2.9861-10.047l8.1169-19.454c0.43322-1.0376 1.0673-1.9888 1.8624-2.7973z" color="#000000" color-rendering="auto" fill-rule="evenodd" image-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="320" height="320" version="1.1" viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg">
<g stroke-width="28"></g>
<g shape-rendering="auto">
<path d="m151.13 0.00104c-28.363 0-54.915 7.9153-77.613 21.537-6.4723-5.2623-14.605-8.1915-23.067-8.1937a8.7661 8.7661 0 0 0-0.0035 0c-20.154 7.3e-4 -36.679 16.528-36.678 36.682a8.7661 8.7661 0 0 0 0 0.0106c0.0099 8.4147 2.9267 16.483 8.1033 22.927-13.825 22.819-21.865 49.572-21.865 78.161a8.7661 8.7661 0 1 0 17.531 0c0-24.702 6.7193-47.748 18.378-67.574 4.5663 1.9846 9.4727 3.1496 14.519 3.1573a8.7661 8.7661 0 0 0 0.01241 0c20.155 6.2e-4 36.683-16.527 36.682-36.682a8.7661 8.7661 0 0 0 0-4e-3c-0.0016-4.9994-1.1387-9.8628-3.0828-14.397 19.717-11.484 42.585-18.095 67.085-18.095a8.7661 8.7661 0 1 0 0-17.531zm-100.69 30.874c5.9129 2e-3 11.191 2.5121 14.836 7.0769a8.7661 8.7661 0 0 0 0.1826 0.21451c2.6715 3.3798 4.1326 7.5531 4.1341 11.863-0.0015 10.677-8.468 19.144-19.144 19.148-4.37-8e-3 -8.6011-1.5088-12-4.2546a8.7661 8.7661 0 0 0-0.01241-9e-3c-4.514-3.6331-7.1358-9.0979-7.1442-14.893 0.0025-10.677 8.4701-19.144 19.148-19.146z" color="#000000" color-rendering="auto" image-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/>
<path d="m168.87 320c28.363 0 54.915-7.9155 77.614-21.538 6.4724 5.2624 14.605 8.1917 23.067 8.1939a8.7662 8.7662 0 0 0 4e-3 0c20.155-7e-4 36.68-16.528 36.679-36.682a8.7662 8.7662 0 0 0 0-0.011c-0.01-8.4149-2.9267-16.484-8.1034-22.927 13.825-22.82 21.866-49.572 21.866-78.162a8.7662 8.7662 0 1 0-17.531 0c0 24.703-6.7194 47.749-18.378 67.575-4.5664-1.9846-9.4728-3.1496-14.519-3.1573a8.7662 8.7662 0 0 0-0.0124 0c-20.155-6.2e-4 -36.683 16.527-36.682 36.682 2e-3 4.9994 1.1387 9.8628 3.0829 14.397-19.717 11.484-42.586 18.095-67.086 18.095a8.7662 8.7662 0 1 0 0 17.531zm100.69-30.875c-5.913 0-11.191-2.5122-14.836-7.0769a8.7662 8.7662 0 0 0-0.18261-0.2146c-2.6715-3.3799-4.1327-7.5531-4.1341-11.863 2e-3 -10.677 8.4681-19.144 19.144-19.148 4.37 8e-3 8.6012 1.5088 12 4.2547a8.7662 8.7662 0 0 0 0.0124 9e-3c4.5141 3.6332 7.1359 9.098 7.1443 14.893-3e-3 10.677-8.4702 19.145-19.148 19.146z" color="#000000" color-rendering="auto" image-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1543.4" height="320" version="1.1" viewBox="0 0 1543.4 320" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(0 -732.36)">
<g stroke-width="28">
<g transform="matrix(-.66287 .69913 -.66371 -.70001 863.46 1410.6)">
<g transform="translate(2.5254 3.0305)"></g>
<g transform="translate(41.25 -30.543)" stroke-width="28"></g>
</g>
<g transform="matrix(.57657 .52719 -.57729 .52786 584.63 346.6)"></g>
<g transform="matrix(.66287 -.69913 .66371 .70001 -543.46 380.47)">
<g transform="translate(2.5254 3.0305)"></g>
<g transform="translate(41.25 -30.543)" stroke-width="28"></g>
</g>
</g>
<g transform="translate(0 732.36)" fill="#305680" stroke-width="1px">
<g fill="#000">
<g transform="translate(-6.1238e-5 -732.36)" shape-rendering="auto">
<path d="m151.13 732.36c-28.363 0-54.915 7.9153-77.613 21.537-6.4723-5.2623-14.605-8.1915-23.067-8.1937a8.7661 8.7661 0 0 0-0.0035 0c-20.154 7.3e-4 -36.679 16.528-36.678 36.682a8.7661 8.7661 0 0 0 0 0.0106c0.0099 8.4147 2.9267 16.483 8.1033 22.927-13.825 22.819-21.865 49.572-21.865 78.161a8.7661 8.7661 0 1 0 17.531 0c0-24.702 6.7193-47.748 18.378-67.574 4.5663 1.9846 9.4727 3.1496 14.519 3.1573a8.7661 8.7661 0 0 0 0.01241 0c20.155 6.2e-4 36.683-16.527 36.682-36.682a8.7661 8.7661 0 0 0 0-4e-3c-0.0016-4.9994-1.1387-9.8628-3.0828-14.397 19.717-11.484 42.585-18.095 67.085-18.095a8.7661 8.7661 0 1 0 0-17.531zm-100.69 30.874c5.9129 2e-3 11.191 2.5121 14.836 7.0769a8.7661 8.7661 0 0 0 0.1826 0.21451c2.6715 3.3798 4.1326 7.5531 4.1341 11.863-0.0015 10.677-8.468 19.144-19.144 19.148-4.37-8e-3 -8.6011-1.5088-12-4.2546a8.7661 8.7661 0 0 0-0.01241-9e-3c-4.514-3.6331-7.1358-9.0979-7.1442-14.893 0.0025-10.677 8.4701-19.144 19.148-19.146z" color="#000000" color-rendering="auto" image-rendering="auto" solid-color="#000000" style="block-progression:tb;isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/>
<path d="m66.992 835.19c-1.492 1.5583-2.3663 3.7103-2.2576 6.0713 0.0962 2.0447 0.91322 4.0204 2.3372 5.5177 6.8051 6.8559 20.223 20.223 20.223 20.223l11.844-11.83s-12.973-12.961-20.176-20.171c-1.604-1.6325-3.7498-2.3141-6.012-2.3243-2.3583-0.0112-4.4673 0.95389-5.9592 2.5122zm32.147 19.983-36.639 36.639c-3.9751 3.976-3.9751 10.421 0 14.397l80.387 80.387c3.9758 3.9759 10.422 3.9763 14.398 0l99.345-99.345c3.9754-3.9764 3.975-10.422-6.7e-4 -14.398l-18.63-18.628-61.758-61.758c-3.976-3.9751-10.421-3.9751-14.397 0l-62.705 62.705zm37.914-37.914s-12.973-12.961-20.176-20.171c-1.604-1.6325-3.7498-2.3141-6.012-2.3243-4.7166-0.0226-8.4341 3.8616-8.2169 8.5834 0.0962 2.0447 0.91322 4.0204 2.3372 5.5177 6.8051 6.8559 20.223 20.223 20.223 20.223l11.844-11.83zm69.193 5.2132s12.961-12.973 20.171-20.176c1.6325-1.604 2.3141-3.7498 2.3243-6.012 0.0225-4.7166-3.8616-8.4341-8.5834-8.2169-2.0447 0.0962-4.0204 0.91322-5.5177 2.3372-6.8559 6.8051-20.223 20.223-20.223 20.223l11.83 11.844zm31.753 31.753s12.961-12.973 20.171-20.176c1.6325-1.604 2.314-3.7498 2.3243-6.012 0.0225-4.7166-3.8616-8.4341-8.5834-8.2169-2.0447 0.0962-4.0204 0.91323-5.5177 2.3372-6.8559 6.8051-20.223 20.223-20.223 20.223l11.83 11.844zm-18.009 69.667s12.973 12.961 20.178 20.169c1.604 1.6324 3.7498 2.314 6.012 2.3243 4.7166 0.0225 8.4342-3.8615 8.2169-8.5834l-2e-3 2e-3c-0.0962-2.0447-0.91415-4.0214-2.3382-5.5186-6.8051-6.8559-20.222-20.222-20.222-20.222l-11.844 11.83zm-37.914 37.914s12.973 12.961 20.178 20.169c1.604 1.6324 3.7498 2.314 6.012 2.3242 4.7166 0.023 8.4342-3.8615 8.2169-8.5834h-2e-3c-0.0962-2.0447-0.91323-4.0205-2.3372-5.5177-6.8051-6.8559-20.223-20.223-20.223-20.223l-11.844 11.83zm-69.667-5.6871s-12.961 12.973-20.169 20.178c-1.6324 1.604-2.314 3.7498-2.3243 6.012-0.02251 4.7166 3.8615 8.4342 8.5834 8.2169h-0.0019c2.0447-0.096 4.0204-0.9132 5.5177-2.3373 6.8561-6.8048 20.223-20.223 20.223-20.223l-11.83-11.846zm-31.753-31.753s-12.961 12.973-20.169 20.178c-1.6324 1.604-2.314 3.7498-2.3243 6.012-0.02251 4.7167 3.8615 8.4342 8.5834 8.2169h-0.0019c2.0447-0.0962 4.0204-0.91322 5.5177-2.3372 6.8561-6.8047 20.223-20.223 20.223-20.223l-11.83-11.846zm87.237-90.554c1.6794-1.7064 3.9669-2.6599 6.2971-2.626 1.6628 0.0237 3.253 0.55012 4.5625 1.5097l16.499 12.1c3.2009 2.297 4.1445 6.6589 2.2308 10.312-1.9137 3.6528-6.1234 5.5243-9.9506 4.4227l6.124 23.948c1.1128 4.3517-1.564 8.9677-5.9833 10.317l-44.642 13.631 8.2456 31.883c1.1728 4.3696-1.5017 9.0445-5.9546 10.407-4.4529 1.3625-8.9756-1.1106-10.068-5.5047l-10.282-39.769c-1.1265-4.3556 1.5493-8.9847 5.9759-10.338l44.661-13.637-4.1219-16.118c-2.7634 3.0643-7.2335 3.8084-10.586 1.7615-3.3531-2.0469-4.6144-6.2896-2.9861-10.047l8.1169-19.454c0.43322-1.0376 1.0673-1.9888 1.8624-2.7973z" color="#000000" color-rendering="auto" fill-rule="evenodd" image-rendering="auto" solid-color="#000000" style="block-progression:tb;isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/>
<path d="m168.87 1052.4c28.363 0 54.915-7.9155 77.614-21.538 6.4724 5.2624 14.605 8.1917 23.067 8.1939a8.7662 8.7662 0 0 0 4e-3 0c20.155-7e-4 36.68-16.528 36.679-36.682a8.7662 8.7662 0 0 0 0-0.011c-0.01-8.4149-2.9267-16.484-8.1034-22.927 13.825-22.82 21.866-49.572 21.866-78.162a8.7662 8.7662 0 1 0-17.531 0c0 24.703-6.7194 47.749-18.378 67.575-4.5664-1.9846-9.4728-3.1496-14.519-3.1573a8.7662 8.7662 0 0 0-0.0124 0c-20.155-6.2e-4 -36.683 16.527-36.682 36.682 2e-3 4.9994 1.1387 9.8628 3.0829 14.397-19.717 11.484-42.586 18.095-67.086 18.095a8.7662 8.7662 0 1 0 0 17.531zm100.69-30.875c-5.913 0-11.191-2.5122-14.836-7.0769a8.7662 8.7662 0 0 0-0.18261-0.2146c-2.6715-3.3799-4.1327-7.5531-4.1341-11.863 2e-3 -10.677 8.4681-19.144 19.144-19.148 4.37 8e-3 8.6012 1.5088 12 4.2547a8.7662 8.7662 0 0 0 0.0124 9e-3c4.5141 3.6332 7.1359 9.098 7.1443 14.893-3e-3 10.677-8.4702 19.145-19.148 19.146z" color="#000000" color-rendering="auto" image-rendering="auto" solid-color="#000000" style="block-progression:tb;isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/>
</g>
<path d="m477.92 93.229h-48.56v134.68h-19.818v-134.68h-48.456v-16.394h116.83v16.394z"/>
<path d="m516.72 129.23q12.762-15.668 33.203-15.668 35.59 0 35.901 40.155v74.188h-19.196v-74.292q-0.10376-12.14-5.603-17.95-5.3955-5.8105-16.913-5.8105-9.3384 0-16.394 4.9805-7.0557 4.9805-10.999 13.074v79.999h-19.196v-159.38h19.196v60.699z"/>
<path d="m635.43 227.91h-19.196v-112.27h19.196v112.27zm-20.752-142.05q0-4.6692 2.8015-7.8857 2.9053-3.2166 8.5083-3.2166 5.603 0 8.5083 3.2166 2.9053 3.2166 2.9053 7.8857 0 4.6692-2.9053 7.782-2.9053 3.1128-8.5083 3.1128-5.603 0-8.5083-3.1128-2.8015-3.1128-2.8015-7.782z"/>
<path d="m684.19 115.64 0.62256 14.111q12.866-16.187 33.618-16.187 35.59 0 35.901 40.155v74.188h-19.196v-74.292q-0.10376-12.14-5.603-17.95-5.3955-5.8105-16.913-5.8105-9.3384 0-16.394 4.9805-7.0557 4.9805-10.999 13.074v79.999h-19.196v-112.27h18.158z"/>
<path d="m778.92 170.84q0-26.251 12.14-41.711 12.14-15.564 32.166-15.564 20.544 0 32.062 14.526l0.93384-12.451h17.535v109.57q0 21.79-12.97 34.344-12.866 12.555-34.656 12.555-12.14 0-23.761-5.188-11.621-5.188-17.743-14.215l9.9609-11.517q12.347 15.253 30.194 15.253 14.008 0 21.79-7.8857 7.8857-7.8858 7.8857-22.205v-9.6497q-11.517 13.281-31.439 13.281-19.714 0-31.958-15.875-12.14-15.875-12.14-43.268zm19.299 2.179q0 18.988 7.782 29.883 7.782 10.791 21.79 10.791 18.158 0 26.666-16.498v-51.257q-8.8196-16.083-26.459-16.083-14.008 0-21.893 10.895-7.8858 10.895-7.8858 32.269z"/>
<path d="m967.98 198.13q0-7.782-5.9143-12.036-5.8106-4.3579-20.441-7.4707-14.526-3.1128-23.138-7.4707-8.5083-4.3579-12.659-10.376-4.0466-6.0181-4.0466-14.319 0-13.8 11.621-23.346 11.725-9.5459 29.883-9.5459 19.092 0 30.92 9.8572 11.932 9.8572 11.932 25.214h-19.299q0-7.8858-6.7444-13.593-6.6406-5.7068-16.809-5.7068-10.48 0-16.394 4.5654-5.9143 4.5654-5.9143 11.932 0 6.9519 5.4993 10.48 5.4993 3.5278 19.818 6.7444 14.423 3.2166 23.346 7.6782t13.177 10.791q4.3579 6.2256 4.3579 15.253 0 15.045-12.036 24.176-12.036 9.0271-31.232 9.0271-13.489 0-23.865-4.773t-16.29-13.281q-5.8105-8.6121-5.8105-18.573h19.196q0.5188 9.6497 7.6782 15.356 7.2632 5.603 19.092 5.603 10.895 0 17.432-4.3579 6.6406-4.4617 6.6406-11.829z"/>
<path d="m1015.2 227.91v-151.07h49.39q24.591 0 36.938 10.168 12.451 10.168 12.451 30.09 0 10.583-6.0181 18.781-6.018 8.0933-16.394 12.555 12.244 3.4241 19.299 13.074 7.1594 9.5459 7.1594 22.827 0 20.337-13.178 31.958-13.178 11.621-37.25 11.621h-52.399zm19.922-70.66v54.37h32.892q13.904 0 21.893-7.1594 8.0933-7.2632 8.0933-19.922 0-27.289-29.675-27.289h-33.203zm0-15.979h30.09q13.074 0 20.856-6.5369 7.8858-6.5369 7.8858-17.743 0-12.451-7.2632-18.054-7.2632-5.7068-22.101-5.7068h-29.468v48.041z"/>
<path d="m1139.5 170.74q0-16.498 6.4331-29.675 6.5369-13.177 18.054-20.337 11.621-7.1594 26.459-7.1594 22.931 0 37.042 15.875 14.215 15.875 14.215 42.23v1.3489q0 16.394-6.3294 29.468-6.2256 12.97-17.95 20.233-11.621 7.2632-26.77 7.2632-22.827 0-37.042-15.875-14.111-15.875-14.111-42.023v-1.3489zm19.299 2.2827q0 18.677 8.6121 29.987 8.7158 11.31 23.242 11.31 14.63 0 23.242-11.414 8.6121-11.517 8.6121-32.166 0-18.469-8.8196-29.883-8.7158-11.517-23.242-11.517-14.215 0-22.931 11.31-8.7158 11.31-8.7158 32.373z"/>
<path d="m1335.1 227.91q-1.6602-3.3203-2.6978-11.829-13.385 13.904-31.958 13.904-16.602 0-27.289-9.3384-10.584-9.4421-10.584-23.865 0-17.535 13.281-27.185 13.385-9.7534 37.561-9.7534h18.677v-8.8196q0-10.065-6.018-15.979-6.0181-6.0181-17.743-6.0181-10.272 0-17.224 5.188t-6.9519 12.555h-19.299q0-8.4045 5.9143-16.187 6.0181-7.8858 16.186-12.451 10.272-4.5654 22.516-4.5654 19.403 0 30.402 9.7534 10.998 9.6497 11.414 26.666v51.672q0 15.46 3.9429 24.591v1.6602h-20.129zm-31.854-14.63q9.0271 0 17.12-4.6692 8.0932-4.6692 11.725-12.14v-23.035h-15.045q-35.278 0-35.278 20.648 0 9.0271 6.0181 14.111 6.0181 5.0842 15.46 5.0842z"/>
<path d="m1435.8 132.87q-4.3579-0.72632-9.4422-0.72632-18.884 0-25.629 16.083v79.688h-19.196v-112.27h18.677l0.3113 12.97q9.4421-15.045 26.77-15.045 5.603 0 8.5083 1.4526v17.847z"/>
<path d="m1448.7 170.84q0-25.836 12.244-41.504 12.244-15.771 32.062-15.771 19.714 0 31.232 13.489v-58.521h19.196v159.38h-17.639l-0.9339-12.036q-11.517 14.111-32.062 14.111-19.507 0-31.854-15.979-12.244-15.979-12.244-41.711v-1.4526zm19.196 2.179q0 19.092 7.8858 29.883 7.8857 10.791 21.79 10.791 18.262 0 26.666-16.394v-51.569q-8.6121-15.875-26.459-15.875-14.111 0-21.997 10.895-7.8858 10.895-7.8858 32.269z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

32
ios/.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
*.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/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

View File

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

View File

@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View File

@ -0,0 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

41
ios/Podfile Normal file
View File

@ -0,0 +1,41 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end

177
ios/Podfile.lock Normal file
View File

@ -0,0 +1,177 @@
PODS:
- device_info_plus (0.0.1):
- Flutter
- Firebase/CoreOnly (10.18.0):
- FirebaseCore (= 10.18.0)
- Firebase/Messaging (10.18.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 10.18.0)
- firebase_core (2.24.2):
- Firebase/CoreOnly (= 10.18.0)
- Flutter
- firebase_messaging (14.7.10):
- Firebase/Messaging (= 10.18.0)
- firebase_core
- Flutter
- FirebaseCore (10.18.0):
- FirebaseCoreInternal (~> 10.0)
- GoogleUtilities/Environment (~> 7.12)
- GoogleUtilities/Logger (~> 7.12)
- FirebaseCoreInternal (10.20.0):
- "GoogleUtilities/NSData+zlib (~> 7.8)"
- FirebaseInstallations (10.20.0):
- FirebaseCore (~> 10.0)
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/UserDefaults (~> 7.8)
- PromisesObjC (~> 2.1)
- FirebaseMessaging (10.18.0):
- FirebaseCore (~> 10.0)
- FirebaseInstallations (~> 10.0)
- GoogleDataTransport (~> 9.2)
- GoogleUtilities/AppDelegateSwizzler (~> 7.8)
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/Reachability (~> 7.8)
- GoogleUtilities/UserDefaults (~> 7.8)
- nanopb (< 2.30910.0, >= 2.30908.0)
- Flutter (1.0.0)
- flutter_inappwebview (0.0.1):
- Flutter
- flutter_inappwebview/Core (= 0.0.1)
- OrderedSet (~> 5.0)
- flutter_inappwebview/Core (0.0.1):
- Flutter
- OrderedSet (~> 5.0)
- flutter_local_notifications (0.0.1):
- Flutter
- flutter_secure_storage (6.0.0):
- Flutter
- geolocator_apple (1.2.0):
- Flutter
- GoogleDataTransport (9.3.0):
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30910.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/AppDelegateSwizzler (7.12.0):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Environment (7.12.0):
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/Logger (7.12.0):
- GoogleUtilities/Environment
- GoogleUtilities/Network (7.12.0):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (7.12.0)"
- GoogleUtilities/Reachability (7.12.0):
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (7.12.0):
- GoogleUtilities/Logger
- image_picker_ios (0.0.1):
- Flutter
- MTBBarcodeScanner (5.0.11)
- nanopb (2.30909.1):
- nanopb/decode (= 2.30909.1)
- nanopb/encode (= 2.30909.1)
- nanopb/decode (2.30909.1)
- nanopb/encode (2.30909.1)
- OrderedSet (5.0.0)
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- PromisesObjC (2.3.1)
- qr_code_scanner (0.2.0):
- Flutter
- MTBBarcodeScanner
- url_launcher_ios (0.0.1):
- Flutter
DEPENDENCIES:
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- Flutter (from `Flutter`)
- flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
SPEC REPOS:
trunk:
- Firebase
- FirebaseCore
- FirebaseCoreInternal
- FirebaseInstallations
- FirebaseMessaging
- GoogleDataTransport
- GoogleUtilities
- MTBBarcodeScanner
- nanopb
- OrderedSet
- PromisesObjC
EXTERNAL SOURCES:
device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios"
firebase_core:
:path: ".symlinks/plugins/firebase_core/ios"
firebase_messaging:
:path: ".symlinks/plugins/firebase_messaging/ios"
Flutter:
:path: Flutter
flutter_inappwebview:
:path: ".symlinks/plugins/flutter_inappwebview/ios"
flutter_local_notifications:
:path: ".symlinks/plugins/flutter_local_notifications/ios"
flutter_secure_storage:
:path: ".symlinks/plugins/flutter_secure_storage/ios"
geolocator_apple:
:path: ".symlinks/plugins/geolocator_apple/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
qr_code_scanner:
:path: ".symlinks/plugins/qr_code_scanner/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
Firebase: 414ad272f8d02dfbf12662a9d43f4bba9bec2a06
firebase_core: 0af4a2b24f62071f9bf283691c0ee41556dcb3f5
firebase_messaging: 90e8a6db84b6e1e876cebce4f30f01dc495e7014
FirebaseCore: 2322423314d92f946219c8791674d2f3345b598f
FirebaseCoreInternal: efeeb171ac02d623bdaefe121539939821e10811
FirebaseInstallations: 558b1da7d65afeb996fd5c814332f013234ece4e
FirebaseMessaging: 9bc34a98d2e0237e1b121915120d4d48ddcf301e
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_inappwebview: 3d32228f1304635e7c028b0d4252937730bbc6cf
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
geolocator_apple: cc556e6844d508c95df1e87e3ea6fa4e58c50401
GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe
GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b
PODFILE CHECKSUM: c4c93c5f6502fe2754f48404d3594bf779584011
COCOAPODS: 1.14.3

View File

@ -0,0 +1,578 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
7814FBD9267B343300D19461 /* TbWebAuthHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7814FBD8267B343200D19461 /* TbWebAuthHandler.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
B5AC1A002B6A93FB0044773A /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5AC19FF2B6A93FB0044773A /* StoreKit.framework */; };
F500F8326F3BBF349D280138 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6358481EC006A0AA65BC8935 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
070516A08514271B237D43F2 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
6358481EC006A0AA65BC8935 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
78018924264ABC4000ABF911 /* Info-Release.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Release.plist"; sourceTree = "<group>"; };
78018925264ABC4000ABF911 /* Info-Debug.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Debug.plist"; sourceTree = "<group>"; };
7814FBD8267B343200D19461 /* TbWebAuthHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TbWebAuthHandler.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
A298BF81631D8CBA51FE65A6 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
AC2915A45ACE7E486FC84F0D /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
B50AAC6C2B63E12600CC8CCD /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
B5AC19FF2B6A93FB0044773A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
B5AC1A002B6A93FB0044773A /* StoreKit.framework in Frameworks */,
F500F8326F3BBF349D280138 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
6DC9651F6A522896561E37DC /* Pods */ = {
isa = PBXGroup;
children = (
070516A08514271B237D43F2 /* Pods-Runner.debug.xcconfig */,
A298BF81631D8CBA51FE65A6 /* Pods-Runner.release.xcconfig */,
AC2915A45ACE7E486FC84F0D /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
6DC9651F6A522896561E37DC /* Pods */,
BB4711A7131D70453FCD2E69 /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
B50AAC6C2B63E12600CC8CCD /* Runner.entitlements */,
7814FBD8267B343200D19461 /* TbWebAuthHandler.swift */,
78018925264ABC4000ABF911 /* Info-Debug.plist */,
78018924264ABC4000ABF911 /* Info-Release.plist */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
BB4711A7131D70453FCD2E69 /* Frameworks */ = {
isa = PBXGroup;
children = (
B5AC19FF2B6A93FB0044773A /* StoreKit.framework */,
6358481EC006A0AA65BC8935 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
7097A270124AE09C59F58A4B /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
675E9C2D528E6C8211A6752E /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
675E9C2D528E6C8211A6752E /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
7097A270124AE09C59F58A4B /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
7814FBD9267B343300D19461 /* TbWebAuthHandler.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-Release.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = org.thingsboard.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = org.thingsboard.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = org.thingsboard.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,30 @@
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
self.registerTbWebAuth()
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private func registerTbWebAuth() {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "tb_web_auth", binaryMessenger: controller.binaryMessenger)
let instance = TbWebAuthHandler()
channel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
instance.handle(call, result: result)
})
}
}

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 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: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

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

View File

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

View File

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

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>ThingsBoard App</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>FirebaseAppDelegateProxyEnabled</key>
<false/>
<key>FirebaseMessagingAutoInitEnabled</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
<string>tel</string>
<string>mailto</string>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSBonjourServices</key>
<array>
<string>_dartobservatory._tcp</string>
</array>
<key>NSCameraUsageDescription</key>
<string>Scan QrCode or take photos using your camera.</string>
<key>NSLocalNetworkUsageDescription</key>
<string>Allow flutter tools on your computer to connect and debug your application.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Get location to place the device on a map.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Get location to place the device on a map.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Access photo library to take existing photos.</string>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>ThingsBoard App</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>FirebaseAppDelegateProxyEnabled</key>
<false/>
<key>FirebaseMessagingAutoInitEnabled</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
<string>tel</string>
<string>mailto</string>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>Scan QrCode or take photos using your camera.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Get location to place the device on a map.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Get location to place the device on a map.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Access photo library to take existing photos.</string>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

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

View File

@ -0,0 +1,12 @@
<?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>aps-environment</key>
<string>development</string>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:demo.thingsboard.io</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,74 @@
import AuthenticationServices
import SafariServices
import Flutter
import UIKit
public class TbWebAuthHandler: NSObject {
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "authenticate" {
let url = URL(string: (call.arguments as! Dictionary<String, AnyObject>)["url"] as! String)!
let callbackURLScheme = (call.arguments as! Dictionary<String, AnyObject>)["callbackUrlScheme"] as! String
var sessionToKeepAlive: Any? = nil // if we do not keep the session alive, it will get closed immediately while showing the dialog
let completionHandler = { (url: URL?, err: Error?) in
sessionToKeepAlive = nil
if let err = err {
if #available(iOS 12, *) {
if case ASWebAuthenticationSessionError.canceledLogin = err {
result(FlutterError(code: "CANCELED", message: "User canceled login", details: nil))
return
}
}
if #available(iOS 11, *) {
if case SFAuthenticationError.canceledLogin = err {
result(FlutterError(code: "CANCELED", message: "User canceled login", details: nil))
return
}
}
result(FlutterError(code: "EUNKNOWN", message: err.localizedDescription, details: nil))
return
}
result(url!.absoluteString)
}
if #available(iOS 12, *) {
let session = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURLScheme, completionHandler: completionHandler)
if #available(iOS 13, *) {
guard let provider = UIApplication.shared.delegate?.window??.rootViewController as? FlutterViewController else {
result(FlutterError(code: "FAILED", message: "Failed to aquire root FlutterViewController" , details: nil))
return
}
session.presentationContextProvider = provider
}
session.start()
sessionToKeepAlive = session
} else if #available(iOS 11, *) {
let session = SFAuthenticationSession(url: url, callbackURLScheme: callbackURLScheme, completionHandler: completionHandler)
session.start()
sessionToKeepAlive = session
} else {
result(FlutterError(code: "FAILED", message: "This plugin does currently not support iOS lower than iOS 11" , details: nil))
}
} else if (call.method == "cleanUpDanglingCalls") {
// we do not keep track of old callbacks on iOS, so nothing to do here
result(nil)
} else {
result(FlutterMethodNotImplemented)
}
}
}
@available(iOS 13, *)
extension FlutterViewController: ASWebAuthenticationPresentationContextProviding {
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return self.view.window!
}
}

View File

@ -0,0 +1,66 @@
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:thingsboard_app/core/auth/auth_routes.dart';
import 'package:thingsboard_app/core/auth/noauth/routes/noauth_routes.dart';
import 'package:thingsboard_app/core/context/tb_context.dart';
import 'package:thingsboard_app/core/init/init_routes.dart';
import 'package:thingsboard_app/modules/alarm/alarm_routes.dart';
import 'package:thingsboard_app/modules/asset/asset_routes.dart';
import 'package:thingsboard_app/modules/audit_log/audit_logs_routes.dart';
import 'package:thingsboard_app/modules/customer/customer_routes.dart';
import 'package:thingsboard_app/modules/dashboard/dashboard_routes.dart';
import 'package:thingsboard_app/modules/device/device_routes.dart';
import 'package:thingsboard_app/modules/home/home_routes.dart';
import 'package:thingsboard_app/modules/notification/routes/notification_routes.dart';
import 'package:thingsboard_app/modules/profile/profile_routes.dart';
import 'package:thingsboard_app/modules/tenant/tenant_routes.dart';
import 'package:thingsboard_app/modules/url/url_routes.dart';
import 'package:thingsboard_app/utils/ui_utils_routes.dart';
class ThingsboardAppRouter {
final router = FluroRouter();
late final _tbContext = TbContext(router);
ThingsboardAppRouter() {
router.notFoundHandler = Handler(
handlerFunc: (BuildContext? context, Map<String, List<String>> params) {
var settings = context!.settings;
return Scaffold(
appBar: AppBar(title: Text('Not Found')),
body: Center(child: Text('Route not defined: ${settings!.name}')),
);
});
InitRoutes(_tbContext).registerRoutes();
AuthRoutes(_tbContext).registerRoutes();
UiUtilsRoutes(_tbContext).registerRoutes();
HomeRoutes(_tbContext).registerRoutes();
ProfileRoutes(_tbContext).registerRoutes();
AssetRoutes(_tbContext).registerRoutes();
DeviceRoutes(_tbContext).registerRoutes();
AlarmRoutes(_tbContext).registerRoutes();
DashboardRoutes(_tbContext).registerRoutes();
AuditLogsRoutes(_tbContext).registerRoutes();
CustomerRoutes(_tbContext).registerRoutes();
TenantRoutes(_tbContext).registerRoutes();
NotificationRoutes(_tbContext).registerRoutes();
UrlPageRoutes(_tbContext).registerRoutes();
NoAuthRoutes(_tbContext).registerRoutes();
}
TbContext get tbContext => _tbContext;
}
abstract class TbRoutes {
final TbContext _tbContext;
TbRoutes(this._tbContext);
void registerRoutes() {
doRegisterRoutes(_tbContext.router);
}
void doRegisterRoutes(FluroRouter router);
TbContext get tbContext => _tbContext;
}

View File

@ -0,0 +1,84 @@
import 'package:flutter/material.dart';
import 'package:thingsboard_app/utils/transition/page_transitions.dart';
const int _tbPrimaryColorValue = 0xFF305680;
const Color _tbPrimaryColor = Color(_tbPrimaryColorValue);
const Color _tbSecondaryColor = Color(0xFF527dad);
const Color _tbDarkPrimaryColor = Color(0xFF9fa8da);
const int _tbTextColorValue = 0xFF282828;
const Color _tbTextColor = Color(_tbTextColorValue);
var tbTypography = Typography.material2018();
const tbMatIndigo = MaterialColor(
_tbPrimaryColorValue,
<int, Color>{
50: Color(0xFFE8EAF6),
100: Color(0xFFC5CAE9),
200: Color(0xFF9FA8DA),
300: Color(0xFF7986CB),
400: Color(0xFF5C6BC0),
500: _tbPrimaryColor,
600: _tbSecondaryColor,
700: Color(0xFF303F9F),
800: Color(0xFF283593),
900: Color(0xFF1A237E),
},
);
const tbDarkMatIndigo = MaterialColor(
_tbPrimaryColorValue,
<int, Color>{
50: Color(0xFFE8EAF6),
100: Color(0xFFC5CAE9),
200: Color(0xFF9FA8DA),
300: Color(0xFF7986CB),
400: Color(0xFF5C6BC0),
500: _tbDarkPrimaryColor,
600: _tbSecondaryColor,
700: Color(0xFF303F9F),
800: _tbPrimaryColor,
900: Color(0xFF1A237E),
},
);
final ThemeData theme = ThemeData(primarySwatch: tbMatIndigo);
ThemeData tbTheme = ThemeData(
useMaterial3: false,
primarySwatch: tbMatIndigo,
colorScheme: theme.colorScheme
.copyWith(primary: tbMatIndigo, secondary: Colors.deepOrange),
scaffoldBackgroundColor: Color(0xFFFAFAFA),
textTheme: tbTypography.black,
primaryTextTheme: tbTypography.black,
typography: tbTypography,
appBarTheme: AppBarTheme(
backgroundColor: Colors.white,
foregroundColor: _tbTextColor,
/* titleTextStyle: TextStyle(
color: _tbTextColor
),
toolbarTextStyle: TextStyle(
color: _tbTextColor
), */
iconTheme: IconThemeData(color: _tbTextColor)),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
backgroundColor: Colors.white,
selectedItemColor: _tbPrimaryColor,
unselectedItemColor: _tbPrimaryColor.withAlpha((255 * 0.38).ceil()),
showSelectedLabels: true,
showUnselectedLabels: true),
pageTransitionsTheme: PageTransitionsTheme(builders: {
TargetPlatform.iOS: FadeOpenPageTransitionsBuilder(),
TargetPlatform.android: FadeOpenPageTransitionsBuilder(),
}));
final ThemeData darkTheme =
ThemeData(primarySwatch: tbDarkMatIndigo, brightness: Brightness.dark);
ThemeData tbDarkTheme = ThemeData(
primarySwatch: tbDarkMatIndigo,
colorScheme: darkTheme.colorScheme.copyWith(secondary: Colors.deepOrange),
brightness: Brightness.dark);

View File

@ -0,0 +1,7 @@
abstract class ThingsboardAppConstants {
static const thingsBoardApiEndpoint = 'http://124.222.96.26:8080';
static const thingsboardOAuth2CallbackUrlScheme = 'org.thingsboard.app.auth';
/// Not for production (only for debugging)
static const thingsboardOAuth2AppSecret = 'Your app secret here';
}

View File

@ -0,0 +1,19 @@
abstract class ThingsboardImage {
static final thingsBoardWithTitle =
'assets/images/thingsboard_with_title.svg';
static final thingsboard = 'assets/images/thingsboard.svg';
static final thingsboardOuter = 'assets/images/thingsboard_outer.svg';
static final thingsboardCenter = 'assets/images/thingsboard_center.svg';
static final dashboardPlaceholder = 'assets/images/dashboard-placeholder.svg';
static final deviceProfilePlaceholder =
'assets/images/device-profile-placeholder.svg';
static final oauth2Logos = <String, String>{
'google-logo': 'assets/images/google-logo.svg',
'github-logo': 'assets/images/github-logo.svg',
'facebook-logo': 'assets/images/facebook-logo.svg',
'apple-logo': 'assets/images/apple-logo.svg',
'qr-code-logo': 'assets/images/qr_code_scanner.svg',
'qr-code': 'assets/images/qr_code_scanner2.svg'
};
}

View File

@ -0,0 +1,4 @@
abstract final class DatabaseKeys {
static const thingsBoardApiEndpointKey = 'thingsBoardApiEndpoint';
static const initialAppLink = 'initialAppLink';
}

View File

@ -0,0 +1,42 @@
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:thingsboard_app/config/routes/router.dart';
import 'package:thingsboard_app/core/auth/login/reset_password_request_page.dart';
import 'package:thingsboard_app/core/auth/login/two_factor_authentication_page.dart';
import 'package:thingsboard_app/core/context/tb_context.dart';
import 'login/login_page.dart';
class AuthRoutes extends TbRoutes {
late var loginHandler = Handler(
handlerFunc: (BuildContext? context, Map<String, dynamic> params) {
return LoginPage(tbContext);
});
late var resetPasswordRequestHandler = Handler(
handlerFunc: (BuildContext? context, Map<String, dynamic> params) {
return ResetPasswordRequestPage(tbContext);
});
late var twoFactorAuthenticationHandler = Handler(
handlerFunc: (BuildContext? context, Map<String, dynamic> params) {
return TwoFactorAuthenticationPage(tbContext);
});
AuthRoutes(TbContext tbContext) : super(tbContext);
@override
void doRegisterRoutes(router) {
router
..define('/login', handler: loginHandler)
..define(
'/login/resetPasswordRequest',
handler: resetPasswordRequestHandler,
)
..define(
'/login/mfa',
handler: twoFactorAuthenticationHandler,
);
}
}

View File

@ -0,0 +1,455 @@
import 'dart:ui';
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:thingsboard_app/constants/assets_path.dart';
import 'package:thingsboard_app/core/context/tb_context.dart';
import 'package:thingsboard_app/core/context/tb_context_widget.dart';
import 'package:thingsboard_app/generated/l10n.dart';
import 'package:thingsboard_app/widgets/tb_progress_indicator.dart';
import 'package:thingsboard_client/thingsboard_client.dart';
import 'login_page_background.dart';
class LoginPage extends TbPageWidget {
LoginPage(TbContext tbContext) : super(tbContext);
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends TbPageState<LoginPage> {
final ButtonStyle _oauth2ButtonWithTextStyle = OutlinedButton.styleFrom(
padding: EdgeInsets.all(16),
alignment: Alignment.centerLeft,
foregroundColor: Colors.black87);
final ButtonStyle _oauth2IconButtonStyle = OutlinedButton.styleFrom(
padding: EdgeInsets.all(16), alignment: Alignment.center);
final _isLoginNotifier = ValueNotifier<bool>(false);
final _showPasswordNotifier = ValueNotifier<bool>(false);
final _loginFormKey = GlobalKey<FormBuilderState>();
@override
void initState() {
super.initState();
if (tbClient.isPreVerificationToken()) {
SchedulerBinding.instance.addPostFrameCallback((_) {
navigateTo('/login/mfa');
});
}
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(children: [
LoginPageBackground(),
Positioned.fill(child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
padding: EdgeInsets.fromLTRB(24, 71, 24, 24),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight - (71 + 24)),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(children: [
SvgPicture.asset(
ThingsboardImage.thingsBoardWithTitle,
height: 25,
colorFilter: ColorFilter.mode(
Theme.of(context).primaryColor,
BlendMode.srcIn),
semanticsLabel:
'${S.of(context).logoDefaultValue}')
]),
SizedBox(height: 32),
Row(children: [
Text('${S.of(context).loginNotification}',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 28,
height: 36 / 28))
]),
SizedBox(height: 48),
if (tbContext.hasOAuthClients)
_buildOAuth2Buttons(
tbContext.oauth2ClientInfos!,
),
Visibility(
visible: !tbContext.hasOAuthClients,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
Container(
padding: const EdgeInsets.symmetric(
vertical: 16),
child: const Center(
child: Text('LOGIN WITH'),
),
),
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
OutlinedButton(
style: _oauth2IconButtonStyle,
onPressed: () async {
try {
final barcode =
await tbContext.navigateTo(
'/qrCodeScan',
transition:
TransitionType.nativeModal,
);
if (barcode != null &&
barcode.code != null) {
tbContext.navigateByAppLink(
barcode.code,
);
} else {}
} catch (e) {
log.error(
'Login with qr code error',
e,
);
}
},
child: Row(
children: [
SvgPicture.asset(
ThingsboardImage.oauth2Logos[
'qr-code-logo']!,
height: 24,
),
const SizedBox(width: 8),
Text(
'Scan QR code',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w400,
),
),
],
),
)
],
)
],
),
),
Padding(
padding: EdgeInsets.only(top: 10, bottom: 16),
child: Row(
children: [
Flexible(child: Divider()),
Padding(
padding:
EdgeInsets.symmetric(horizontal: 16),
child: Text('${S.of(context).OR}'),
),
Flexible(child: Divider())
],
),
),
FormBuilder(
key: _loginFormKey,
autovalidateMode: AutovalidateMode.disabled,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
FormBuilderTextField(
name: 'username',
keyboardType:
TextInputType.emailAddress,
validator:
FormBuilderValidators.compose([
FormBuilderValidators.required(
errorText:
'${S.of(context).emailRequireText}'),
FormBuilderValidators.email(
errorText:
'${S.of(context).emailInvalidText}')
]),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText:
'${S.of(context).email}'),
),
SizedBox(height: 28),
ValueListenableBuilder(
valueListenable:
_showPasswordNotifier,
builder: (BuildContext context,
bool showPassword, child) {
return FormBuilderTextField(
name: 'password',
obscureText: !showPassword,
validator: FormBuilderValidators
.compose([
FormBuilderValidators.required(
errorText:
'${S.of(context).passwordRequireText}')
]),
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(showPassword
? Icons.visibility
: Icons.visibility_off),
onPressed: () {
_showPasswordNotifier
.value =
!_showPasswordNotifier
.value;
},
),
border: OutlineInputBorder(),
labelText:
'${S.of(context).password}'),
);
})
],
)),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
_forgotPassword();
},
child: Text(
'${S.of(context).passwordForgotText}',
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary,
letterSpacing: 1,
fontSize: 12,
height: 16 / 12),
),
)
],
),
Spacer(),
ElevatedButton(
child: Text('${S.of(context).login}'),
style: ElevatedButton.styleFrom(
padding:
EdgeInsets.symmetric(vertical: 16)),
onPressed: () {
_login();
},
),
SizedBox(height: 48)
]),
)));
},
)),
ValueListenableBuilder<bool>(
valueListenable: _isLoginNotifier,
builder: (BuildContext context, bool loading, child) {
if (loading) {
var data = MediaQuery.of(context);
var bottomPadding = data.padding.top;
bottomPadding += kToolbarHeight;
return SizedBox.expand(
child: ClipRect(
child: BackdropFilter(
filter:
ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
decoration: new BoxDecoration(
color:
Colors.grey.shade200.withOpacity(0.2)),
child: Container(
padding:
EdgeInsets.only(bottom: bottomPadding),
alignment: Alignment.center,
child: TbProgressIndicator(size: 50.0),
),
))));
} else {
return SizedBox.shrink();
}
})
]));
}
Widget _buildOAuth2Buttons(List<OAuth2ClientInfo> clients) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 16),
child: const Center(
child: Text('LOGIN WITH'),
),
),
Row(
children: [
...clients
.asMap()
.map(
(index, client) => MapEntry(
index,
_buildOAuth2Button(
client,
clients.length == 2 ? client.name : null,
true,
index == clients.length - 1,
),
),
)
.values
.toList(),
const SizedBox(width: 8),
Expanded(
child: OutlinedButton(
style: _oauth2IconButtonStyle,
onPressed: () async {
try {
final barcode = await tbContext.navigateTo(
'/qrCodeScan',
transition: TransitionType.nativeModal,
);
if (barcode != null && barcode.code != null) {
tbContext.navigateByAppLink(
barcode.code,
);
} else {}
} catch (e) {
log.error(
'Login with qr code error',
e,
);
}
},
child: SvgPicture.asset(
ThingsboardImage.oauth2Logos['qr-code']!,
height: 24,
),
),
),
],
)
],
);
}
Widget _buildOAuth2Button(
OAuth2ClientInfo client, String? text, bool expand, bool isLast) {
Widget? icon;
if (client.icon != null) {
if (ThingsboardImage.oauth2Logos.containsKey(client.icon)) {
icon = SvgPicture.asset(ThingsboardImage.oauth2Logos[client.icon]!,
height: 24);
} else {
String strIcon = client.icon!;
if (strIcon.startsWith('mdi:')) {
strIcon = strIcon.substring(4);
}
var iconData = MdiIcons.fromString(strIcon);
if (iconData != null) {
icon =
Icon(iconData, size: 24, color: Theme.of(context).primaryColor);
}
}
}
if (icon == null) {
icon = Icon(Icons.login, size: 24, color: Theme.of(context).primaryColor);
}
Widget button;
bool iconOnly = text == null;
if (iconOnly) {
button = OutlinedButton(
style: _oauth2IconButtonStyle,
onPressed: () => _oauth2ButtonPressed(client),
child: icon);
} else {
button = OutlinedButton(
style: _oauth2ButtonWithTextStyle,
onPressed: () => _oauth2ButtonPressed(client),
child: Stack(children: [
Align(alignment: Alignment.centerLeft, child: icon),
Container(
height: 24,
child: Align(
alignment: Alignment.center,
child: Text(text, textAlign: TextAlign.center)),
)
]));
}
if (expand) {
return Expanded(
child: Padding(
padding: EdgeInsets.only(right: isLast ? 0 : 8),
child: button,
));
} else {
return Padding(
padding: EdgeInsets.only(bottom: isLast ? 0 : 8),
child: button,
);
}
}
void _oauth2ButtonPressed(OAuth2ClientInfo client) async {
_isLoginNotifier.value = true;
try {
final result = await tbContext.oauth2Client.authenticate(client.url);
if (result.success) {
await tbClient.setUserFromJwtToken(
result.accessToken, result.refreshToken, true);
} else {
_isLoginNotifier.value = false;
showErrorNotification(result.error!);
}
} catch (e) {
log.error('Auth Error:', e);
_isLoginNotifier.value = false;
}
}
void _login() async {
FocusScope.of(context).unfocus();
if (_loginFormKey.currentState?.saveAndValidate() ?? false) {
var formValue = _loginFormKey.currentState!.value;
String username = formValue['username'];
String password = formValue['password'];
_isLoginNotifier.value = true;
try {
await tbClient.login(LoginRequest(username, password));
} catch (e) {
_isLoginNotifier.value = false;
if (!(e is ThingsboardError) ||
e.errorCode == ThingsBoardErrorCode.general) {
await tbContext.onFatalError(e);
}
}
}
}
void _forgotPassword() async {
navigateTo('/login/resetPasswordRequest');
}
}

View File

@ -0,0 +1,42 @@
import 'package:flutter/material.dart';
class LoginPageBackground extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SizedBox.expand(
child: CustomPaint(
painter:
_LoginPageBackgroundPainter(color: Theme.of(context).primaryColor),
));
}
}
class _LoginPageBackgroundPainter extends CustomPainter {
final Color color;
const _LoginPageBackgroundPainter({required this.color});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()..color = color.withAlpha(14);
paint.style = PaintingStyle.fill;
var topPath = Path();
topPath.moveTo(0, 0);
topPath.lineTo(size.width / 2, 0);
topPath.lineTo(0, size.height / 10);
topPath.close();
canvas.drawPath(topPath, paint);
var bottomPath = Path();
bottomPath.moveTo(0, size.height * 0.98);
bottomPath.lineTo(size.width, size.height * 0.78);
bottomPath.lineTo(size.width, size.height);
bottomPath.lineTo(0, size.height);
bottomPath.close();
canvas.drawPath(bottomPath, paint);
}
@override
bool shouldRepaint(covariant _LoginPageBackgroundPainter oldDelegate) {
return color != oldDelegate.color;
}
}

View File

@ -0,0 +1,118 @@
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:thingsboard_app/core/auth/login/login_page_background.dart';
import 'package:thingsboard_app/core/context/tb_context.dart';
import 'package:thingsboard_app/core/context/tb_context_widget.dart';
import 'package:thingsboard_app/generated/l10n.dart';
import 'package:thingsboard_app/widgets/tb_app_bar.dart';
import 'package:thingsboard_app/widgets/tb_progress_indicator.dart';
class ResetPasswordRequestPage extends TbPageWidget {
ResetPasswordRequestPage(TbContext tbContext) : super(tbContext);
@override
_ResetPasswordRequestPageState createState() =>
_ResetPasswordRequestPageState();
}
class _ResetPasswordRequestPageState
extends TbPageState<ResetPasswordRequestPage> {
final _isLoadingNotifier = ValueNotifier<bool>(false);
final _resetPasswordFormKey = GlobalKey<FormBuilderState>();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(children: [
LoginPageBackground(),
SizedBox.expand(
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: TbAppBar(
tbContext,
title: Text('${S.of(context).passwordReset}'),
),
body: Stack(children: [
SizedBox.expand(
child: Padding(
padding: EdgeInsets.all(24),
child: FormBuilder(
key: _resetPasswordFormKey,
autovalidateMode: AutovalidateMode.disabled,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(height: 16),
Text(
'${S.of(context).passwordResetText}',
textAlign: TextAlign.center,
style: TextStyle(
color: Color(0xFFAFAFAF),
fontSize: 14,
height: 24 / 14),
),
SizedBox(height: 61),
FormBuilderTextField(
name: 'email',
autofocus: true,
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(
errorText:
'${S.of(context).emailRequireText}'),
FormBuilderValidators.email(
errorText:
'${S.of(context).emailInvalidText}')
]),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: '${S.of(context).email} *'),
),
Spacer(),
ElevatedButton(
child: Text(
'${S.of(context).requestPasswordReset}'),
style: ElevatedButton.styleFrom(
padding:
EdgeInsets.symmetric(vertical: 16)),
onPressed: () {
_requestPasswordReset();
},
)
])))),
ValueListenableBuilder<bool>(
valueListenable: _isLoadingNotifier,
builder: (BuildContext context, bool loading, child) {
if (loading) {
return SizedBox.expand(
child: Container(
color: Color(0x99FFFFFF),
child: Center(child: TbProgressIndicator(size: 50.0)),
));
} else {
return SizedBox.shrink();
}
})
])))
]));
}
void _requestPasswordReset() async {
FocusScope.of(context).unfocus();
if (_resetPasswordFormKey.currentState?.saveAndValidate() ?? false) {
var formValue = _resetPasswordFormKey.currentState!.value;
String email = formValue['email'];
_isLoadingNotifier.value = true;
try {
await Future.delayed(Duration(milliseconds: 300));
await tbClient.sendResetPasswordLink(email);
_isLoadingNotifier.value = false;
showSuccessNotification(
'${S.of(context).passwordResetLinkSuccessfullySentNotification}');
} catch (e) {
_isLoadingNotifier.value = false;
}
}
}
}

View File

@ -0,0 +1,459 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:thingsboard_app/core/auth/login/login_page_background.dart';
import 'package:thingsboard_app/core/context/tb_context.dart';
import 'package:thingsboard_app/core/context/tb_context_widget.dart';
import 'package:thingsboard_app/widgets/tb_app_bar.dart';
import 'package:thingsboard_app/generated/l10n.dart';
import 'package:thingsboard_client/thingsboard_client.dart';
import 'package:collection/collection.dart';
typedef ProviderDescFunction = String Function(
BuildContext context, String? contact);
typedef TextFunction = String Function(BuildContext context);
class TwoFactorAuthProviderLoginData {
TextFunction nameFunction;
ProviderDescFunction descFunction;
TextFunction placeholderFunction;
String icon;
TwoFactorAuthProviderLoginData(
{required this.nameFunction,
required this.descFunction,
required this.placeholderFunction,
required this.icon});
}
final Map<TwoFaProviderType, TwoFactorAuthProviderLoginData>
twoFactorAuthProvidersLoginData = {
TwoFaProviderType.TOTP: TwoFactorAuthProviderLoginData(
nameFunction: (context) => S.of(context).mfaProviderTopt,
descFunction: (context, contact) => S.of(context).totpAuthDescription,
placeholderFunction: (context) => S.of(context).toptAuthPlaceholder,
icon: 'cellphone-key'),
TwoFaProviderType.SMS: TwoFactorAuthProviderLoginData(
nameFunction: (context) => S.of(context).mfaProviderSms,
descFunction: (context, contact) =>
S.of(context).smsAuthDescription(contact ?? ''),
placeholderFunction: (context) => S.of(context).smsAuthPlaceholder,
icon: 'message-reply-text-outline'),
TwoFaProviderType.EMAIL: TwoFactorAuthProviderLoginData(
nameFunction: (context) => S.of(context).mfaProviderEmail,
descFunction: (context, contact) =>
S.of(context).emailAuthDescription(contact ?? ''),
placeholderFunction: (context) => S.of(context).emailAuthPlaceholder,
icon: 'email-outline'),
TwoFaProviderType.BACKUP_CODE: TwoFactorAuthProviderLoginData(
nameFunction: (context) => S.of(context).mfaProviderBackupCode,
descFunction: (context, contact) =>
S.of(context).backupCodeAuthDescription,
placeholderFunction: (context) => S.of(context).backupCodeAuthPlaceholder,
icon: 'lock-outline')
};
class TwoFactorAuthenticationPage extends TbPageWidget {
TwoFactorAuthenticationPage(TbContext tbContext) : super(tbContext);
@override
_TwoFactorAuthenticationPageState createState() =>
_TwoFactorAuthenticationPageState();
}
class _TwoFactorAuthenticationPageState
extends TbPageState<TwoFactorAuthenticationPage> {
final _twoFactorAuthFormKey = GlobalKey<FormBuilderState>();
ValueNotifier<TwoFaProviderType?> _selectedProvider =
ValueNotifier<TwoFaProviderType?>(null);
TwoFaProviderType? _prevProvider;
int? _minVerificationPeriod;
List<TwoFaProviderType> _allowProviders = [];
ValueNotifier<bool> _disableSendButton = ValueNotifier<bool>(false);
ValueNotifier<bool> _showResendAction = ValueNotifier<bool>(false);
ValueNotifier<bool> _hideResendButton = ValueNotifier<bool>(true);
Timer? _timer;
Timer? _tooManyRequestsTimer;
ValueNotifier<int> _countDownTime = ValueNotifier<int>(0);
@override
void initState() {
super.initState();
var providersInfo = tbContext.twoFactorAuthProviders;
TwoFaProviderType.values.forEach((provider) {
var providerConfig =
providersInfo!.firstWhereOrNull((config) => config.type == provider);
if (providerConfig != null) {
if (providerConfig.isDefault) {
_minVerificationPeriod =
providerConfig.minVerificationCodeSendPeriod ?? 30;
_selectedProvider.value = providerConfig.type;
}
_allowProviders.add(providerConfig.type);
}
});
if (this._selectedProvider.value != TwoFaProviderType.TOTP) {
_sendCode();
_showResendAction.value = true;
}
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
_updatedTime();
});
}
@override
void dispose() {
if (_timer != null) {
_timer!.cancel();
}
if (_tooManyRequestsTimer != null) {
_tooManyRequestsTimer!.cancel();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
// ignore: deprecated_member_use
return WillPopScope(
onWillPop: () async {
return await _goBack();
},
child: Scaffold(
backgroundColor: Colors.white,
resizeToAvoidBottomInset: false,
body: Stack(children: [
LoginPageBackground(),
SizedBox.expand(
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: TbAppBar(
tbContext,
title: Text('${S.of(context).verifyYourIdentity}'),
),
body: Stack(children: [
SizedBox.expand(
child: Padding(
padding: EdgeInsets.all(24),
child: ValueListenableBuilder<TwoFaProviderType?>(
valueListenable: _selectedProvider,
builder: (context, providerType, _widget) {
if (providerType == null) {
var children = <Widget>[
Padding(
padding: EdgeInsets.only(bottom: 16),
child: Text(
'${S.of(context).selectWayToVerify}',
style: TextStyle(
color: Colors.black87,
fontSize: 16,
height: 24 / 16)))
];
_allowProviders.forEach((type) {
var providerData =
twoFactorAuthProvidersLoginData[
type]!;
Widget? icon;
var iconData = MdiIcons.fromString(
providerData.icon);
if (iconData != null) {
icon = Icon(iconData,
size: 24,
color:
Theme.of(context).primaryColor);
} else {
icon = Icon(Icons.login,
size: 24,
color:
Theme.of(context).primaryColor);
}
children.add(Container(
padding:
EdgeInsets.symmetric(vertical: 8),
child: OutlinedButton.icon(
style: OutlinedButton.styleFrom(
padding: EdgeInsets.all(16),
alignment:
Alignment.centerLeft),
onPressed: () async =>
await _selectProvider(type),
icon: icon,
label: Text(providerData
.nameFunction(context)))));
});
return ListView(
padding:
EdgeInsets.symmetric(vertical: 8),
children: children,
);
} else {
var providerConfig = tbContext
.twoFactorAuthProviders
?.firstWhereOrNull((config) =>
config.type == providerType);
if (providerConfig == null) {
return SizedBox.shrink();
}
var providerDescription =
twoFactorAuthProvidersLoginData[
providerType]!
.descFunction;
return FormBuilder(
key: _twoFactorAuthFormKey,
autovalidateMode:
AutovalidateMode.disabled,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
SizedBox(height: 16),
Text(
providerDescription(context,
providerConfig.contact),
textAlign: TextAlign.start,
style: TextStyle(
color: Color(0xFF7F7F7F),
fontSize: 14,
height: 24 / 14),
),
SizedBox(height: 16),
_buildVerificationCodeField(
context, providerType),
Spacer(),
ValueListenableBuilder<bool>(
valueListenable:
_disableSendButton,
builder: (context,
disableSendButton,
_widget) {
return ElevatedButton(
child: Text(
'${S.of(context).continueText}'),
style: ElevatedButton
.styleFrom(
padding: EdgeInsets
.symmetric(
vertical:
16)),
onPressed: disableSendButton
? null
: () =>
_sendVerificationCode(
context));
}),
SizedBox(height: 16),
SizedBox(
height: 49,
child: Row(
mainAxisSize:
MainAxisSize.max,
children: [
ValueListenableBuilder<
bool>(
valueListenable:
_showResendAction,
builder: (context,
showResendActionValue,
_widget) {
if (showResendActionValue) {
return Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
ValueListenableBuilder<
int>(
valueListenable:
_countDownTime,
builder: (context,
countDown,
_widget) {
if (countDown >
0) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 12),
child: Text(
S.of(context).resendCodeWait(countDown),
textAlign: TextAlign.center,
style: TextStyle(color: Color(0xFF7F7F7F), fontSize: 12, height: 24 / 12),
),
);
} else {
return SizedBox.shrink();
}
}),
ValueListenableBuilder<
bool>(
valueListenable:
_hideResendButton,
builder: (context,
hideResendButton,
_widget) {
if (!hideResendButton) {
return TextButton(
child: Text('${S.of(context).resendCode}'),
style: ElevatedButton.styleFrom(padding: EdgeInsets.symmetric(vertical: 16)),
onPressed: () {
_sendCode();
},
);
} else {
return SizedBox.shrink();
}
})
]));
} else {
return SizedBox
.shrink();
}
}),
if (_allowProviders
.length >
1)
Expanded(
child: TextButton(
child: Text(
'${S.of(context).tryAnotherWay}'),
style: ElevatedButton.styleFrom(
padding: EdgeInsets
.symmetric(
vertical:
16)),
onPressed:
() async {
await _selectProvider(
null);
},
))
]))
]));
}
})))
]),
),
)
])));
}
FormBuilderTextField _buildVerificationCodeField(
BuildContext context, TwoFaProviderType providerType) {
int maxLengthInput = 6;
TextInputType keyboardType = TextInputType.number;
String pattern = '[0-9]*';
if (providerType == TwoFaProviderType.BACKUP_CODE) {
maxLengthInput = 8;
pattern = '[0-9abcdef]*';
keyboardType = TextInputType.text;
}
List<FormFieldValidator<String>> validators = [
FormBuilderValidators.required(
errorText: '${S.of(context).verificationCodeInvalid}'),
FormBuilderValidators.equalLength(maxLengthInput,
errorText: '${S.of(context).verificationCodeInvalid}'),
FormBuilderValidators.match(pattern,
errorText: '${S.of(context).verificationCodeInvalid}')
];
var providerFormData = twoFactorAuthProvidersLoginData[providerType]!;
return FormBuilderTextField(
name: 'verificationCode',
autofocus: true,
maxLength: maxLengthInput,
keyboardType: keyboardType,
validator: FormBuilderValidators.compose(validators),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: providerFormData.placeholderFunction(context)));
}
Future<void> _sendVerificationCode(BuildContext context) async {
FocusScope.of(context).unfocus();
if (_twoFactorAuthFormKey.currentState?.saveAndValidate() ?? false) {
var formValue = _twoFactorAuthFormKey.currentState!.value;
String verificationCode = formValue['verificationCode'];
try {
await tbClient.checkTwoFaVerificationCode(
_selectedProvider.value!, verificationCode,
requestConfig: RequestConfig(ignoreErrors: true));
} catch (e) {
if (e is ThingsboardError) {
if (e.status == 400) {
_twoFactorAuthFormKey.currentState!.fields['verificationCode']!
.invalidate(S.of(context).verificationCodeIncorrect);
} else if (e.status == 429) {
_twoFactorAuthFormKey.currentState!.fields['verificationCode']!
.invalidate(S.of(context).verificationCodeManyRequest);
_disableSendButton.value = true;
if (_tooManyRequestsTimer != null) {
_tooManyRequestsTimer!.cancel();
}
_tooManyRequestsTimer = Timer(Duration(seconds: 5), () {
_twoFactorAuthFormKey.currentState!.fields['verificationCode']!
.validate();
_disableSendButton.value = false;
});
} else {
showErrorNotification(e.message ?? 'Code verification failed!');
}
} else {
showErrorNotification('Code verification failed!');
}
}
}
}
Future<void> _selectProvider(TwoFaProviderType? type) async {
_prevProvider = type == null ? _selectedProvider.value : null;
_selectedProvider.value = type;
_showResendAction.value = false;
if (type != null) {
var providersInfo = tbContext.twoFactorAuthProviders;
var providerConfig =
providersInfo!.firstWhereOrNull((config) => config.type == type)!;
if (type != TwoFaProviderType.TOTP &&
type != TwoFaProviderType.BACKUP_CODE) {
_sendCode();
_showResendAction.value = true;
_minVerificationPeriod =
providerConfig.minVerificationCodeSendPeriod ?? 30;
}
}
}
Future<void> _sendCode() async {
_hideResendButton.value = true;
_countDownTime.value = 0;
try {
await tbContext.tbClient
.getTwoFactorAuthService()
.requestTwoFaVerificationCode(_selectedProvider.value!,
requestConfig: RequestConfig(ignoreErrors: true));
} catch (e) {
} finally {
_countDownTime.value = _minVerificationPeriod!;
}
}
Future<bool> _goBack() async {
if (_prevProvider != null) {
await _selectProvider(_prevProvider);
} else {
tbClient.logout(requestConfig: RequestConfig(ignoreErrors: true));
}
return false;
}
void _updatedTime() {
if (_countDownTime.value > 0) {
_countDownTime.value--;
if (_countDownTime.value == 0) {
_hideResendButton.value = false;
}
}
}
}

View File

@ -0,0 +1,21 @@
import 'package:flutter/foundation.dart';
import 'package:thingsboard_client/thingsboard_client.dart';
abstract interface class INoAuthRemoteDatasource {
Future<LoginResponse> getJwtToken({
required String host,
required String key,
});
Future<void> setUserFromJwtToken(LoginResponse loginData);
Future<void> logout({RequestConfig? requestConfig, bool notifyUser = true});
Future<void> reInit({
required String endpoint,
required VoidCallback onDone,
required ErrorCallback onError,
});
bool isAuthenticated();
}

View File

@ -0,0 +1,74 @@
import 'dart:ui';
import 'package:thingsboard_app/core/auth/noauth/data/datasource/remote/i_noauth_remote_datasource.dart';
import 'package:thingsboard_app/core/context/tb_context.dart';
import 'package:thingsboard_app/core/logger/tb_logger.dart';
import 'package:thingsboard_client/thingsboard_client.dart';
class NoAuthRemoteDatasource implements INoAuthRemoteDatasource {
const NoAuthRemoteDatasource({
required this.thingsboardClient,
required this.tbLogger,
required this.tbContext,
});
final ThingsboardClient thingsboardClient;
final TbLogger tbLogger;
final TbContext tbContext;
@override
Future<LoginResponse> getJwtToken({
required String host,
required String key,
}) async {
try {
final data = await thingsboardClient.getLoginDataBySecretKey(
host: host,
key: key,
);
return data;
} catch (e) {
tbLogger.error('NoAuthRemoteDatasource:getJwtToken() message $e');
rethrow;
}
}
@override
Future<void> setUserFromJwtToken(LoginResponse loginData) async {
await thingsboardClient.setUserFromJwtToken(
loginData.token,
loginData.refreshToken,
false,
);
}
@override
Future<void> logout({
RequestConfig? requestConfig,
bool notifyUser = true,
}) async {
await tbContext.logout(
requestConfig: requestConfig,
notifyUser: notifyUser,
);
}
@override
Future<void> reInit({
required String endpoint,
required VoidCallback onDone,
required ErrorCallback onError,
}) async {
await tbContext.reInit(
endpoint: endpoint,
onDone: onDone,
onError: onError,
);
}
@override
bool isAuthenticated() {
return tbContext.isAuthenticated;
}
}

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