Compare commits
64 Commits
_archived-
...
_archived-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02b4a73de7 | ||
|
|
0f0a647c3c | ||
|
|
86de81adb3 | ||
|
|
7d32be57a9 | ||
|
|
bc1c8589c3 | ||
|
|
6b49e1d5e4 | ||
|
|
7790eea069 | ||
|
|
dd9d990e3f | ||
|
|
504e0af11a | ||
|
|
7248e6096d | ||
|
|
c183c819fc | ||
|
|
28122fa003 | ||
|
|
e2e9f78705 | ||
|
|
49444b3056 | ||
|
|
4e8ac3fafb | ||
|
|
ff6cd50cc5 | ||
|
|
67df1c2b7b | ||
|
|
c464724bc8 | ||
|
|
6af87aa69c | ||
|
|
fad1873369 | ||
|
|
ee533bd76a | ||
|
|
6b5d4c3958 | ||
|
|
4c81a280c8 | ||
|
|
368f9ef617 | ||
|
|
deeda09ca3 | ||
|
|
28a70074c8 | ||
|
|
0b7c618f33 | ||
|
|
0118d37232 | ||
|
|
4f5ba12f2d | ||
|
|
2275b582b4 | ||
|
|
f635df038a | ||
|
|
36c3acdf2c | ||
|
|
6704fc7cbb | ||
|
|
34f345c237 | ||
|
|
127b798acd | ||
|
|
c2e39982a1 | ||
|
|
e1d5e29365 | ||
|
|
70dbf3966d | ||
|
|
493ea01f85 | ||
|
|
cf0cc8b305 | ||
|
|
46e292193c | ||
|
|
19d429d739 | ||
|
|
451294ba08 | ||
|
|
f3182675de | ||
|
|
80a0a4ef63 | ||
|
|
23117fd96f | ||
|
|
d6b6fde480 | ||
|
|
44892e5b03 | ||
|
|
fd247a4e6b | ||
|
|
19ef1f65db | ||
|
|
268e794f5d | ||
|
|
7f88684d8c | ||
|
|
17b4b62133 | ||
|
|
4d3b33d877 | ||
|
|
1916d4f922 | ||
|
|
3ea1f05460 | ||
|
|
1eaa306a70 | ||
|
|
9fa683e7e4 | ||
|
|
2292013507 | ||
|
|
13b60b92bf | ||
|
|
09ace76b82 | ||
|
|
e198424da8 | ||
|
|
a39cd2990f | ||
|
|
fec99d526a |
@@ -7,7 +7,13 @@ on:
|
||||
- v5
|
||||
tags:
|
||||
- "v*"
|
||||
paths:
|
||||
- haskell/**
|
||||
- .github/workflows/build_haskell.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- haskell/**
|
||||
- .github/workflows/build_haskell.yml
|
||||
|
||||
jobs:
|
||||
prepare-release:
|
||||
32
.github/workflows/ci_dart.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Run CI
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # every sunday at midnight
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test on ${{ matrix.os }} / ${{ matrix.flutter }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/repo_support
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
flutter: [stable, beta, dev]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '12.x'
|
||||
- uses: subosito/flutter-action@v1
|
||||
with:
|
||||
channel: ${{ matrix.flutter }}
|
||||
- run: flutter --version
|
||||
- run: flutter upgrade
|
||||
- run: dart --version
|
||||
- run: dart pub get
|
||||
- run: dart run tool/run_ci.dart
|
||||
51
.gitignore
vendored
@@ -43,9 +43,54 @@ cabal.project.local~
|
||||
*.cabal
|
||||
stack.yaml.lock
|
||||
|
||||
# Idris
|
||||
*.ibc
|
||||
|
||||
# chat database
|
||||
*.db
|
||||
*.db.bak
|
||||
|
||||
# Misc
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# VS Code
|
||||
.vscode/
|
||||
|
||||
# Flutter/Dart/Pub
|
||||
**/doc/api/
|
||||
**/ios/Flutter/.last_build_id
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
.packages
|
||||
.pub-cache/
|
||||
.pub/
|
||||
build/
|
||||
# Default behavior, only keep it for apps
|
||||
pubspec.lock
|
||||
|
||||
# Web
|
||||
lib/generated_plugin_registrant.dart
|
||||
|
||||
# Symbolication
|
||||
app.*.symbols
|
||||
|
||||
# Obfuscation
|
||||
app.*.map.json
|
||||
|
||||
# Android Studio build artifacts
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
|
||||
|
||||
44
packages/analysis_options.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
include: package:lints/recommended.yaml
|
||||
|
||||
linter:
|
||||
rules:
|
||||
prefer_single_quotes: true
|
||||
constant_identifier_names: false
|
||||
always_declare_return_types: true
|
||||
avoid_dynamic_calls: true
|
||||
avoid_empty_else: true
|
||||
avoid_relative_lib_imports: true
|
||||
avoid_shadowing_type_parameters: true
|
||||
avoid_slow_async_io: true
|
||||
avoid_types_as_parameter_names: true
|
||||
await_only_futures: true
|
||||
camel_case_extensions: true
|
||||
camel_case_types: true
|
||||
cancel_subscriptions: true
|
||||
curly_braces_in_flow_control_structures: true
|
||||
directives_ordering: true
|
||||
empty_catches: true
|
||||
hash_and_equals: true
|
||||
iterable_contains_unrelated_type: true
|
||||
list_remove_unrelated_type: true
|
||||
no_adjacent_strings_in_list: true
|
||||
no_duplicate_case_values: true
|
||||
package_api_docs: true
|
||||
package_prefixed_library_names: true
|
||||
prefer_generic_function_type_aliases: true
|
||||
prefer_is_empty: true
|
||||
prefer_is_not_empty: true
|
||||
prefer_iterable_whereType: true
|
||||
prefer_typing_uninitialized_variables: true
|
||||
sort_child_properties_last: true
|
||||
test_types_in_equals: true
|
||||
throw_in_finally: true
|
||||
unawaited_futures: true
|
||||
unnecessary_import: true
|
||||
unnecessary_null_aware_assignments: true
|
||||
unnecessary_statements: true
|
||||
unnecessary_type_check: true
|
||||
unrelated_type_equality_checks: true
|
||||
unsafe_html: true
|
||||
use_full_hex_values_for_flutter_colors: true
|
||||
valid_regexps: true
|
||||
23
packages/repo_support/.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# See https://www.dartlang.org/guides/libraries/private-files
|
||||
|
||||
# Files and directories created by pub
|
||||
.dart_tool/
|
||||
.packages
|
||||
.pub/
|
||||
build/
|
||||
# If you're building an application, you may want to check-in your pubspec.lock
|
||||
pubspec.lock
|
||||
|
||||
# Directory created by dartdoc
|
||||
# If you don't generate documentation locally you can remove this line.
|
||||
doc/api/
|
||||
|
||||
# Intellij
|
||||
*.idea/
|
||||
*.iml
|
||||
|
||||
# VS code
|
||||
.vscode
|
||||
|
||||
# Local
|
||||
.local/
|
||||
8
packages/repo_support/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# repo_support
|
||||
|
||||
App flutter utils repo support
|
||||
|
||||
```
|
||||
dart run tool/run_ci.dart
|
||||
|
||||
```
|
||||
11
packages/repo_support/pubspec.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
name: simplex_repo_support
|
||||
description: SimpleX build tools
|
||||
version: 0.2.0
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
|
||||
dev_dependencies:
|
||||
dev_test:
|
||||
|
||||
14
packages/repo_support/tool/run_ci.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
// ignore_for_file: prefer_double_quotes
|
||||
|
||||
import 'package:dev_test/package.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
||||
Future main() async {
|
||||
for (var dir in [
|
||||
'simplex_app',
|
||||
'simplexmq',
|
||||
'repo_support',
|
||||
]) {
|
||||
await packageRunCi(join('..', dir));
|
||||
}
|
||||
}
|
||||
2
packages/simplex_app/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Keep for apps
|
||||
!pubspec.lock
|
||||
10
packages/simplex_app/.metadata
Normal 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: 4cc385b4b84ac2f816d939a49ea1f328c4e0b48e
|
||||
channel: stable
|
||||
|
||||
project_type: app
|
||||
16
packages/simplex_app/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# simplex_app
|
||||
|
||||
A new Flutter project.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This project is a starting point for a Flutter application.
|
||||
|
||||
A few resources to get you started if this is your first Flutter project:
|
||||
|
||||
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
|
||||
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
|
||||
|
||||
For help getting started with Flutter, view our
|
||||
[online documentation](https://flutter.dev/docs), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
45
packages/simplex_app/analysis_options.yaml
Normal file
@@ -0,0 +1,45 @@
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
linter:
|
||||
# https://dart-lang.github.io/linter/lints/index.html.
|
||||
rules:
|
||||
prefer_single_quotes: true
|
||||
always_declare_return_types: true
|
||||
avoid_dynamic_calls: true
|
||||
avoid_empty_else: true
|
||||
avoid_relative_lib_imports: true
|
||||
avoid_shadowing_type_parameters: true
|
||||
avoid_slow_async_io: true
|
||||
avoid_types_as_parameter_names: true
|
||||
await_only_futures: true
|
||||
camel_case_extensions: true
|
||||
camel_case_types: true
|
||||
cancel_subscriptions: true
|
||||
curly_braces_in_flow_control_structures: true
|
||||
directives_ordering: true
|
||||
empty_catches: true
|
||||
hash_and_equals: true
|
||||
iterable_contains_unrelated_type: true
|
||||
list_remove_unrelated_type: true
|
||||
no_adjacent_strings_in_list: true
|
||||
no_duplicate_case_values: true
|
||||
package_api_docs: true
|
||||
package_prefixed_library_names: true
|
||||
prefer_generic_function_type_aliases: true
|
||||
prefer_is_empty: true
|
||||
prefer_is_not_empty: true
|
||||
prefer_iterable_whereType: true
|
||||
prefer_typing_uninitialized_variables: true
|
||||
sort_child_properties_last: true
|
||||
test_types_in_equals: true
|
||||
throw_in_finally: true
|
||||
unawaited_futures: true
|
||||
unnecessary_import: true
|
||||
unnecessary_null_aware_assignments: true
|
||||
unnecessary_statements: true
|
||||
unnecessary_type_check: true
|
||||
unrelated_type_equality_checks: true
|
||||
unsafe_html: true
|
||||
use_full_hex_values_for_flutter_colors: true
|
||||
valid_regexps: true
|
||||
13
packages/simplex_app/android/.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
|
||||
# Remember to never publicly share your keystore.
|
||||
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||
key.properties
|
||||
**/*.keystore
|
||||
**/*.jks
|
||||
68
packages/simplex_app/android/app/build.gradle
Normal file
@@ -0,0 +1,68 @@
|
||||
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 30
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
|
||||
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 "com.example.simplex_chat"
|
||||
minSdkVersion 20
|
||||
targetSdkVersion 30
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source '../..'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.simplex_chat">
|
||||
<!-- 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"/>
|
||||
</manifest>
|
||||
@@ -0,0 +1,41 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.simplex_chat">
|
||||
<application
|
||||
android:label="SimpleX Chat"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- 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>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.example.simplex_chat
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity: FlutterActivity() {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
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>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
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>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.simplex_chat">
|
||||
<!-- 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"/>
|
||||
</manifest>
|
||||
29
packages/simplex_app/android/build.gradle
Normal file
@@ -0,0 +1,29 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.2.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.buildDir = '../build'
|
||||
subprojects {
|
||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||
project.evaluationDependsOn(':app')
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
3
packages/simplex_app/android/gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
6
packages/simplex_app/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal 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-6.9-all.zip
|
||||
11
packages/simplex_app/android/settings.gradle
Normal 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"
|
||||
BIN
packages/simplex_app/assets/code.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
packages/simplex_app/assets/dp.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
12
packages/simplex_app/assets/logo.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg width="815" height="233" viewBox="0 0 815 233" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M40.5683 66.9141C43.9954 66.9141 47.376 67.2323 50.7104 67.8687C54.0448 68.5051 57.2403 69.3234 60.2968 70.3235C63.3533 71.3236 66.2014 72.4601 68.8411 73.7329C71.4809 75.0058 73.9122 76.2786 76.1351 77.5515L66.132 96.0987L65.9952 95.9474C65.6001 95.5596 64.6732 94.9282 63.2144 94.0531C61.5472 93.053 59.4632 92.0074 56.9624 90.9164C54.4616 89.8254 51.7293 88.8708 48.7654 88.0525C45.8015 87.2342 42.8376 86.8251 39.8737 86.8251C31.723 86.8251 27.6476 89.5072 27.6476 94.8713C27.6476 96.5079 28.0876 97.8716 28.9675 98.9627C29.8474 100.054 31.1441 101.031 32.8576 101.895C34.5711 102.758 36.7245 103.554 39.318 104.281C41.9114 105.009 44.9216 105.827 48.3486 106.736C53.0723 108.009 57.3329 109.395 61.1304 110.896C64.9279 112.396 68.1465 114.26 70.7862 116.487C73.4259 118.715 75.4636 121.419 76.8993 124.602C78.3349 127.784 79.0527 131.602 79.0527 136.057C79.0527 141.512 78.0107 146.126 75.9267 149.899C73.8427 153.673 71.0872 156.718 67.6602 159.037C64.2332 161.355 60.2968 163.037 55.8509 164.083C51.4051 165.128 46.8203 165.651 42.0966 165.651C38.4844 165.651 34.7795 165.378 30.982 164.833C27.1845 164.287 23.4796 163.492 19.8674 162.446C16.2551 161.401 12.7587 160.15 9.37796 158.696C5.99726 157.241 2.87128 155.559 0 153.65L10.0032 134.148L10.1812 134.338C10.6877 134.825 11.8324 135.625 13.6154 136.739C15.6531 138.012 18.177 139.285 21.1872 140.558C24.1974 141.83 27.555 142.967 31.2599 143.967C34.9647 144.967 38.7159 145.467 42.5134 145.467C50.5715 145.467 54.6006 143.058 54.6006 138.239C54.6006 136.421 53.9985 134.921 52.7944 133.739C51.5903 132.557 49.9231 131.489 47.7928 130.534C45.6625 129.579 43.1386 128.693 40.221 127.875C37.3034 127.056 34.1311 126.147 30.7041 125.147C26.1657 123.783 22.2292 122.306 18.8948 120.715C15.5605 119.124 12.805 117.283 10.6284 115.192C8.45174 113.1 6.83086 110.691 5.76571 107.964C4.70056 105.236 4.16798 102.054 4.16798 98.4171C4.16798 93.3257 5.14051 88.8253 7.08557 84.9158C9.03063 81.0063 11.6703 77.7106 15.0047 75.0285C18.3391 72.3464 22.2061 70.3235 26.6056 68.9597C31.0051 67.5959 35.6594 66.9141 40.5683 66.9141ZM131.47 67.7323V164.56H108.685V67.7323H131.47ZM191.39 67.7323L216.954 118.328L242.657 67.7323H267.248V164.56H244.463V106.6L223.067 148.74H210.841L189.445 106.6V164.56H166.66V67.7323H191.39ZM419.925 67.7323V144.922H467.718V164.56H397.14V67.7323H419.925ZM560.072 67.7323V87.3706H514.78V106.191H553.681V124.329H514.78V144.922H561.323V164.56H491.995V67.7323H560.072ZM341.818 67.7323L343.378 67.7677C347.5 67.9563 351.31 68.8991 354.809 70.5962C358.745 72.5055 362.126 75.0058 364.951 78.097C367.776 81.1882 369.999 84.6885 371.62 88.598C373.24 92.5075 374.051 96.4624 374.051 100.463C374.051 104.736 373.287 108.827 371.758 112.737C370.23 116.646 368.1 120.147 365.368 123.238C362.635 126.329 359.324 128.784 355.434 130.602C351.976 132.218 348.189 133.116 344.072 133.296L342.513 133.33H322.507V164.56H299.722V67.7323H341.818ZM340.29 87.3706H322.507V113.828H341.124C343.81 113.828 346.125 112.691 348.07 110.418C350.016 108.145 350.988 104.827 350.988 100.463C350.988 98.1898 350.687 96.2351 350.085 94.5986C349.483 92.9621 348.672 91.5983 347.654 90.5073C346.635 89.4163 345.477 88.6207 344.18 88.1207C342.884 87.6206 341.587 87.3706 340.29 87.3706Z" fill="#062D56"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M642.628 136.08L680.309 173.782L699.513 154.567L699.506 154.561L737.917 116.134L700.236 78.4367L700.243 78.4334L681.404 59.5826L642.993 98.014L642.99 98.0104L681.401 59.5829L643.725 21.881L662.929 2.6652L700.605 40.3673L739.016 1.93511L757.855 20.7859L719.443 59.2176L757.121 96.918L795.533 58.4875L814.373 77.3382L775.959 115.768L813.643 153.471L794.439 172.687L756.756 134.984L718.348 173.415L756.031 211.119L736.827 230.335L699.144 192.63L660.74 231.065L641.901 212.214L680.306 173.78L642.625 136.083L642.628 136.08Z" fill="#07B4B9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M604.77 59.7651L642.446 97.4664L680.856 59.035L699.696 77.8858L661.285 116.317L698.966 154.019L679.762 173.235L642.081 135.532L603.675 173.965L584.836 155.114L623.243 116.682L585.566 78.9809L604.77 59.7651Z" fill="#062D56"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="815" height="233" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
4
packages/simplex_app/assets/menu.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="18" viewBox="0 0 24 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 12H15" stroke="#0D1333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M3 6H21" stroke="#0D1333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 306 B |
BIN
packages/simplex_app/assets/simpleX.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
17
packages/simplex_app/assets/simpleX.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024" viewBox="0 0 1024 1024">
|
||||
<defs>
|
||||
<clipPath id="clip-path">
|
||||
<rect id="Rectangle_2" data-name="Rectangle 2" width="2971" height="843" transform="translate(0 0.292)" fill="#fff"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip-simpleX">
|
||||
<rect width="1024" height="1024"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="simpleX" clip-path="url(#clip-simpleX)">
|
||||
<g id="logo" transform="translate(-2047 89.708)" clip-path="url(#clip-path)">
|
||||
<path id="Path_6" data-name="Path 6" d="M147.9,66.914a198.176,198.176,0,0,1,36.975,3.455,284.4,284.4,0,0,1,34.949,8.885,253.446,253.446,0,0,1,31.15,12.34q14.436,6.911,26.592,13.821L241.1,172.542l-.5-.548q-2.161-2.105-10.138-6.856a202.569,202.569,0,0,0-22.793-11.353,224.542,224.542,0,0,0-29.884-10.365,122.159,122.159,0,0,0-32.417-4.442q-44.573,0-44.573,29.122,0,8.885,4.812,14.808t14.182,10.613a133.233,133.233,0,0,0,23.553,8.636q14.182,3.952,32.923,8.885a437.841,437.841,0,0,1,46.6,15.056q20.767,8.143,35.2,20.236A82.161,82.161,0,0,1,280.355,275.7q7.851,17.275,7.851,41.459,0,29.615-11.4,50.1a94.466,94.466,0,0,1-30.137,33.073A129.137,129.137,0,0,1,203.618,418.6a219.939,219.939,0,0,1-50.145,5.675,287.161,287.161,0,0,1-40.521-2.961,299.792,299.792,0,0,1-40.521-8.639A327.515,327.515,0,0,1,34.19,399.1,215.84,215.84,0,0,1,0,380.839l36.469-70.584.649.688q2.77,2.644,12.52,8.69a199.248,199.248,0,0,0,27.6,13.822,287.382,287.382,0,0,0,36.722,12.338,157.851,157.851,0,0,0,41.027,5.429q44.067,0,44.067-26.16a21.773,21.773,0,0,0-6.585-16.287q-6.585-6.417-18.235-11.6a201.006,201.006,0,0,0-27.6-9.624q-15.955-4.446-34.7-9.874a304.855,304.855,0,0,1-43.054-16.041Q50.651,253,38.748,241.647a72.548,72.548,0,0,1-17.728-26.16Q15.2,200.676,15.2,180.933q0-27.641,10.637-48.865A105.947,105.947,0,0,1,54.7,96.283,126.757,126.757,0,0,1,97,74.318,172.123,172.123,0,0,1,147.9,66.914Zm331.4,2.961v350.45H396.237V69.875Zm218.452,0L790.957,253,884.663,69.875h89.652v350.45H891.247V210.55l-78,152.518H768.671l-78-152.518V420.325H607.6V69.875Zm833.178,0V349.249h174.241v71.076H1447.868V69.875Zm510.939,0v71.077H1876.752V209.07h141.823v65.647H1876.752v74.533h169.683v71.076H1793.684V69.875Zm-795.7,0,5.687.128a106.112,106.112,0,0,1,41.674,10.237,121.073,121.073,0,0,1,36.975,27.148,129.172,129.172,0,0,1,24.313,38.006,110.611,110.611,0,0,1,8.863,42.943,120.122,120.122,0,0,1-8.36,44.423,126.219,126.219,0,0,1-23.3,38.006,109.262,109.262,0,0,1-77.64,36.4l-5.684.123h-72.937V420.325h-83.068V69.875Zm-5.571,71.077h-64.832V236.71h67.873q14.689,0,25.323-12.342t10.638-36.03q0-12.341-3.292-21.225a43.245,43.245,0,0,0-8.863-14.808,33.932,33.932,0,0,0-12.665-8.638A39.4,39.4,0,0,0,1240.607,140.953Z" transform="translate(0 175.261)" fill="#062d56" fill-rule="evenodd"/>
|
||||
<path id="Path_7" data-name="Path 7" d="M644.551,487.448,781.926,623.9l70.013-69.545-.026-.022L991.95,415.257,854.575,278.818l.025-.012-68.682-68.227-140.036,139.1-.011-.013L785.908,210.581,648.551,74.126,718.563,4.578,855.92,141.033,995.957,1.935l68.682,68.227L924.6,209.258l137.364,136.45L1202,206.616l68.685,68.227L1130.641,413.932l137.386,136.459-70.013,69.549L1060.632,483.481,920.607,622.575l137.382,136.463-70.013,69.549L850.594,692.12,710.583,831.228,641.9,763,781.916,623.9,644.541,487.458Z" transform="translate(1698.3 5.061)" fill="#07b4b9" fill-rule="evenodd"/>
|
||||
<path id="Path_8" data-name="Path 8" d="M657.51,61.677,794.867,198.13,934.9,59.035l68.686,68.227L863.549,266.357l137.375,136.455-70.013,69.549L793.536,335.9,653.518,475l-68.682-68.228,140.022-139.1L587.5,131.225Z" transform="translate(1547.321 154.623)" fill="#062d56" fill-rule="evenodd"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
BIN
packages/simplex_app/assets/x.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
33
packages/simplex_app/ios/.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.moved-aside
|
||||
*.pbxuser
|
||||
*.perspectivev3
|
||||
**/*sync/
|
||||
.sconsign.dblite
|
||||
.tags*
|
||||
**/.vagrant/
|
||||
**/DerivedData/
|
||||
Icon?
|
||||
**/Pods/
|
||||
**/.symlinks/
|
||||
profile
|
||||
xcuserdata
|
||||
**/.generated/
|
||||
Flutter/App.framework
|
||||
Flutter/Flutter.framework
|
||||
Flutter/Flutter.podspec
|
||||
Flutter/Generated.xcconfig
|
||||
Flutter/ephemeral/
|
||||
Flutter/app.flx
|
||||
Flutter/app.zip
|
||||
Flutter/flutter_assets/
|
||||
Flutter/flutter_export_environment.sh
|
||||
ServiceDefinitions.json
|
||||
Runner/GeneratedPluginRegistrant.*
|
||||
|
||||
# Exceptions to above rules.
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.pbxuser
|
||||
!default.perspectivev3
|
||||
26
packages/simplex_app/ios/Flutter/AppFrameworkInfo.plist
Normal 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>9.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
2
packages/simplex_app/ios/Flutter/Debug.xcconfig
Normal file
@@ -0,0 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
2
packages/simplex_app/ios/Flutter/Release.xcconfig
Normal file
@@ -0,0 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
41
packages/simplex_app/ios/Podfile
Normal file
@@ -0,0 +1,41 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '9.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
|
||||
91
packages/simplex_app/ios/Podfile.lock
Normal file
@@ -0,0 +1,91 @@
|
||||
PODS:
|
||||
- DKImagePickerController/Core (4.3.2):
|
||||
- DKImagePickerController/ImageDataManager
|
||||
- DKImagePickerController/Resource
|
||||
- DKImagePickerController/ImageDataManager (4.3.2)
|
||||
- DKImagePickerController/PhotoGallery (4.3.2):
|
||||
- DKImagePickerController/Core
|
||||
- DKPhotoGallery
|
||||
- DKImagePickerController/Resource (4.3.2)
|
||||
- DKPhotoGallery (0.0.17):
|
||||
- DKPhotoGallery/Core (= 0.0.17)
|
||||
- DKPhotoGallery/Model (= 0.0.17)
|
||||
- DKPhotoGallery/Preview (= 0.0.17)
|
||||
- DKPhotoGallery/Resource (= 0.0.17)
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Core (0.0.17):
|
||||
- DKPhotoGallery/Model
|
||||
- DKPhotoGallery/Preview
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Model (0.0.17):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Preview (0.0.17):
|
||||
- DKPhotoGallery/Model
|
||||
- DKPhotoGallery/Resource
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Resource (0.0.17):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- file_picker (0.0.1):
|
||||
- DKImagePickerController/PhotoGallery
|
||||
- Flutter
|
||||
- Flutter (1.0.0)
|
||||
- image_picker (0.0.1):
|
||||
- Flutter
|
||||
- MTBBarcodeScanner (5.0.11)
|
||||
- qr_code_scanner (0.2.0):
|
||||
- Flutter
|
||||
- MTBBarcodeScanner
|
||||
- SDWebImage (5.12.0):
|
||||
- SDWebImage/Core (= 5.12.0)
|
||||
- SDWebImage/Core (5.12.0)
|
||||
- share (0.0.1):
|
||||
- Flutter
|
||||
- SwiftyGif (5.4.0)
|
||||
|
||||
DEPENDENCIES:
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- image_picker (from `.symlinks/plugins/image_picker/ios`)
|
||||
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
|
||||
- share (from `.symlinks/plugins/share/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- DKImagePickerController
|
||||
- DKPhotoGallery
|
||||
- MTBBarcodeScanner
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
file_picker:
|
||||
:path: ".symlinks/plugins/file_picker/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
image_picker:
|
||||
:path: ".symlinks/plugins/image_picker/ios"
|
||||
qr_code_scanner:
|
||||
:path: ".symlinks/plugins/qr_code_scanner/ios"
|
||||
share:
|
||||
:path: ".symlinks/plugins/share/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
|
||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
|
||||
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
|
||||
image_picker: 50e7c7ff960e5f58faa4d1f4af84a771c671bc4a
|
||||
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
||||
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
|
||||
SDWebImage: 4ea20cca2986adc5aacde07aa686742fd4c67a37
|
||||
share: 0b2c3e82132f5888bccca3351c504d0003b3b410
|
||||
SwiftyGif: 5d4af95df24caf1c570dbbcb32a3b8a0763bc6d7
|
||||
|
||||
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
|
||||
|
||||
COCOAPODS: 1.11.0
|
||||
539
packages/simplex_app/ios/Runner.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,539 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
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 */; };
|
||||
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 */; };
|
||||
AE3860269BF424274DA84C73 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B0B8C697FBAC21A75BCBB5A /* 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 */
|
||||
031FDA72D548A2F92732ADA4 /* 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>"; };
|
||||
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>"; };
|
||||
2FD15BE67425B26EB06BB4AE /* 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>"; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
4B0B8C697FBAC21A75BCBB5A /* 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>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
7E09253D517C54DFA8ECEE7A /* 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>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
AE3860269BF424274DA84C73 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
415DD71D33C5D1C1BBA9E62B /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B0B8C697FBAC21A75BCBB5A /* Pods_Runner.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5A0F33679D6B606E9775E794 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7E09253D517C54DFA8ECEE7A /* Pods-Runner.debug.xcconfig */,
|
||||
2FD15BE67425B26EB06BB4AE /* Pods-Runner.release.xcconfig */,
|
||||
031FDA72D548A2F92732ADA4 /* Pods-Runner.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
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 */,
|
||||
5A0F33679D6B606E9775E794 /* Pods */,
|
||||
415DD71D33C5D1C1BBA9E62B /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146EF1CF9000F007C117D /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
97C147021CF9000F007C117D /* Info.plist */,
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||
);
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
AA6465993557C0297F2D0450 /* [CP] Check Pods Manifest.lock */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
B4CC1E87FA75B139B238C706 /* [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 = 1020;
|
||||
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;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
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";
|
||||
};
|
||||
AA6465993557C0297F2D0450 /* [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;
|
||||
};
|
||||
B4CC1E87FA75B139B238C706 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m 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 = 9.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.simplexChat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
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 = 9.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 = 9.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
97C147061CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.simplexChat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147071CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.simplexChat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
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 */;
|
||||
}
|
||||
7
packages/simplex_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
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>
|
||||
10
packages/simplex_app/ios/Runner.xcworkspace/contents.xcworkspacedata
generated
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
13
packages/simplex_app/ios/Runner/AppDelegate.swift
Normal file
@@ -0,0 +1,13 @@
|
||||
import UIKit
|
||||
import Flutter
|
||||
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 824 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
23
packages/simplex_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
BIN
packages/simplex_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
packages/simplex_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
packages/simplex_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
5
packages/simplex_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
vendored
Normal 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.
|
||||
@@ -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>
|
||||
26
packages/simplex_app/ios/Runner/Base.lproj/Main.storyboard
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Flutter View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
49
packages/simplex_app/ios/Runner/Info.plist
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>io.flutter.embedded_views_preview</key>
|
||||
<true/>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>This app needs camera access to scan QR codes</string>
|
||||
<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>simplex_chat</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
1
packages/simplex_app/ios/Runner/Runner-Bridging-Header.h
Normal file
@@ -0,0 +1 @@
|
||||
#import "GeneratedPluginRegistrant.h"
|
||||
78
packages/simplex_app/lib/animations/bottom_animation.dart
Normal file
@@ -0,0 +1,78 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Animator extends StatefulWidget {
|
||||
final Widget child;
|
||||
final Duration time;
|
||||
|
||||
const Animator(this.child, this.time, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_AnimatorState createState() => _AnimatorState();
|
||||
}
|
||||
|
||||
class _AnimatorState extends State<Animator>
|
||||
with SingleTickerProviderStateMixin {
|
||||
Timer? timer;
|
||||
AnimationController? animationController;
|
||||
Animation? animation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
animationController = AnimationController(
|
||||
duration: const Duration(milliseconds: 290), vsync: this);
|
||||
animation =
|
||||
CurvedAnimation(parent: animationController!, curve: Curves.easeInOut);
|
||||
timer = Timer(widget.time, animationController!.forward);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
animationController!.dispose();
|
||||
super.dispose();
|
||||
timer!.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: animation!,
|
||||
child: widget.child,
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
return Opacity(
|
||||
opacity: animation!.value,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0.0, (1 - animation!.value) * 20),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Timer? timer;
|
||||
Duration duration = const Duration();
|
||||
|
||||
Duration wait() {
|
||||
if (timer == null || !timer!.isActive) {
|
||||
timer = Timer(const Duration(microseconds: 120), () {
|
||||
duration = const Duration();
|
||||
});
|
||||
}
|
||||
duration += const Duration(milliseconds: 100);
|
||||
return duration;
|
||||
}
|
||||
|
||||
class WidgetAnimator extends StatelessWidget {
|
||||
final Widget child;
|
||||
|
||||
const WidgetAnimator({required this.child, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Animator(child, wait());
|
||||
}
|
||||
}
|
||||
70
packages/simplex_app/lib/animations/entrance_fader.dart
Normal file
@@ -0,0 +1,70 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class EntranceFader extends StatefulWidget {
|
||||
/// Child to be animated on entrance
|
||||
final Widget child;
|
||||
|
||||
/// Delay after which the animation will start
|
||||
final Duration delay;
|
||||
|
||||
/// Duration of entrance animation
|
||||
final Duration duration;
|
||||
|
||||
/// Starting point from which the widget will fade to its default position
|
||||
final Offset offset;
|
||||
|
||||
const EntranceFader({
|
||||
Key? key,
|
||||
required this.child,
|
||||
this.delay = const Duration(milliseconds: 0),
|
||||
this.duration = const Duration(milliseconds: 400),
|
||||
this.offset = const Offset(0.0, 32.0),
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
EntranceFaderState createState() {
|
||||
return EntranceFaderState();
|
||||
}
|
||||
}
|
||||
|
||||
class EntranceFaderState extends State<EntranceFader>
|
||||
with SingleTickerProviderStateMixin {
|
||||
AnimationController? _controller;
|
||||
Animation? _dxAnimation;
|
||||
Animation? _dyAnimation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(vsync: this, duration: widget.duration);
|
||||
_dxAnimation =
|
||||
Tween(begin: widget.offset.dx, end: 0.0).animate(_controller!);
|
||||
_dyAnimation =
|
||||
Tween(begin: widget.offset.dy, end: 0.0).animate(_controller!);
|
||||
Future.delayed(widget.delay, () {
|
||||
if (mounted) {
|
||||
_controller!.forward();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller!.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: _controller!,
|
||||
builder: (context, child) => Opacity(
|
||||
opacity: _controller!.value,
|
||||
child: Transform.translate(
|
||||
offset: Offset(_dxAnimation!.value, _dyAnimation!.value),
|
||||
child: widget.child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
12
packages/simplex_app/lib/app_routes.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
/// All the named routes are mentioned here
|
||||
|
||||
class AppRoutes {
|
||||
static const splash = '/splash';
|
||||
static const intro = '/intro';
|
||||
static const setupProfile = '/setupProfile';
|
||||
static const home = '/home';
|
||||
static const addContact = '/addContact';
|
||||
static const addContactWeb = '/addContactWeb';
|
||||
static const scanInvitation = '/ScanInvitation';
|
||||
static const addGroup = '/addGroup';
|
||||
}
|
||||
24
packages/simplex_app/lib/constants.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// colors
|
||||
const kPrimaryColor = Color(0xff062d56);
|
||||
const kSecondaryColor = Color(0xff07b4b9);
|
||||
|
||||
// text styles
|
||||
const TextStyle kHeadingStyle = TextStyle(
|
||||
fontSize: 28.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 1.3,
|
||||
color: kPrimaryColor,
|
||||
);
|
||||
|
||||
const TextStyle kMediumHeadingStyle = TextStyle(
|
||||
fontSize: 20.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: kPrimaryColor,
|
||||
);
|
||||
|
||||
const TextStyle kSmallHeadingStyle = TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
18
packages/simplex_app/lib/custom_scroll_behavior.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ScrollBehaviorModified extends ScrollBehavior {
|
||||
const ScrollBehaviorModified();
|
||||
@override
|
||||
ScrollPhysics getScrollPhysics(BuildContext context) {
|
||||
switch (getPlatform(context)) {
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
case TargetPlatform.android:
|
||||
return const BouncingScrollPhysics();
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.linux:
|
||||
case TargetPlatform.windows:
|
||||
return const ClampingScrollPhysics();
|
||||
}
|
||||
}
|
||||
}
|
||||
20
packages/simplex_app/lib/generated_plugin_registrant.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// ignore_for_file: directives_ordering
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
import 'package:file_picker/_internal/file_picker_web.dart';
|
||||
import 'package:image_picker_for_web/image_picker_for_web.dart';
|
||||
import 'package:shared_preferences_web/shared_preferences_web.dart';
|
||||
|
||||
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
|
||||
|
||||
// ignore: public_member_api_docs
|
||||
void registerPlugins(Registrar registrar) {
|
||||
FilePickerWeb.registerWith(registrar);
|
||||
ImagePickerPlugin.registerWith(registrar);
|
||||
SharedPreferencesPlugin.registerWith(registrar);
|
||||
registrar.registerMessageHandler();
|
||||
}
|
||||
67
packages/simplex_app/lib/main.dart
Normal file
@@ -0,0 +1,67 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:simplex_chat/app_routes.dart';
|
||||
import 'package:simplex_chat/constants.dart';
|
||||
import 'package:simplex_chat/custom_scroll_behavior.dart';
|
||||
import 'package:simplex_chat/providers/drawer_providers.dart';
|
||||
import 'package:simplex_chat/views/contacts/add_contact_view.dart';
|
||||
import 'package:simplex_chat/views/contacts/add_contact_web.dart';
|
||||
import 'package:simplex_chat/views/group/add_group_view.dart';
|
||||
import 'package:simplex_chat/views/home/home_view.dart';
|
||||
import 'package:simplex_chat/views/onboarding/intro_view.dart';
|
||||
import 'package:simplex_chat/views/scan_invitation/scan_invitation_view.dart';
|
||||
import 'package:simplex_chat/views/setup_profile_view.dart';
|
||||
import 'package:simplex_chat/views/splash_screen.dart';
|
||||
import 'package:url_strategy/url_strategy.dart';
|
||||
|
||||
/// Basic Structure is setup on [Providers]
|
||||
/// Navigations are [namedRoutes]
|
||||
|
||||
void main() {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
setPathUrlStrategy();
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ThemeData(
|
||||
primarySwatch: Colors.teal,
|
||||
primaryColor: kPrimaryColor,
|
||||
);
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => DrawerProvider()),
|
||||
],
|
||||
child: Consumer<DrawerProvider>(
|
||||
builder: (context, drawerProvider, chidl) => MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'SimpleX Chat',
|
||||
theme: theme.copyWith(
|
||||
colorScheme: theme.colorScheme.copyWith(secondary: kPrimaryColor),
|
||||
primaryColorLight: Colors.white,
|
||||
),
|
||||
builder: (context, widget) {
|
||||
return ScrollConfiguration(
|
||||
behavior: const ScrollBehaviorModified(), child: widget!);
|
||||
},
|
||||
initialRoute: AppRoutes.splash,
|
||||
routes: <String, WidgetBuilder>{
|
||||
AppRoutes.splash: (_) => const SplashScreen(),
|
||||
AppRoutes.intro: (_) => const IntroView(),
|
||||
AppRoutes.setupProfile: (_) => const SetupProfileView(),
|
||||
AppRoutes.home: (_) => const HomeView(),
|
||||
AppRoutes.addContact: (_) => const AddContactView(),
|
||||
AppRoutes.addContactWeb: (_) => const AddContactWeb(),
|
||||
AppRoutes.scanInvitation: (_) => const ScanInvitationView(),
|
||||
AppRoutes.addGroup: (_) => const AddGroupView(),
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
44
packages/simplex_app/lib/model/contact.dart
Normal file
@@ -0,0 +1,44 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class Contact {
|
||||
final String? name;
|
||||
final String? subtitle;
|
||||
final String? photo;
|
||||
final bool? isGroup;
|
||||
|
||||
Contact({
|
||||
required this.name,
|
||||
required this.subtitle,
|
||||
this.photo = '',
|
||||
this.isGroup = false,
|
||||
});
|
||||
|
||||
factory Contact.fromJson(Map<String, dynamic> json) {
|
||||
return Contact(
|
||||
name: json['name'],
|
||||
subtitle: json['subtitle'],
|
||||
photo: json['photo'],
|
||||
isGroup: json['isGroup'],
|
||||
);
|
||||
}
|
||||
|
||||
static Map<String, dynamic> toJson(Contact contact) {
|
||||
return {
|
||||
'name': contact.name,
|
||||
'subtitle': contact.subtitle,
|
||||
'photo': contact.photo,
|
||||
'isGroup': false,
|
||||
};
|
||||
}
|
||||
|
||||
static String encode(List<Contact> contacts) => json.encode(
|
||||
contacts
|
||||
.map<Map<String, dynamic>>((contact) => Contact.toJson(contact))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
static List<Contact> decode(String contacts) =>
|
||||
(json.decode(contacts) as List<dynamic>)
|
||||
.map<Contact>((item) => Contact.fromJson(item))
|
||||
.toList();
|
||||
}
|
||||
48
packages/simplex_app/lib/model/group.dart
Normal file
@@ -0,0 +1,48 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class Group {
|
||||
final String? name;
|
||||
final String? subtitle;
|
||||
final String? photo;
|
||||
final List<dynamic>? members;
|
||||
final bool? isGroup;
|
||||
|
||||
Group({
|
||||
required this.name,
|
||||
required this.subtitle,
|
||||
this.photo = '',
|
||||
this.isGroup = true,
|
||||
this.members = const [],
|
||||
});
|
||||
|
||||
factory Group.fromJson(Map<String, dynamic> json) {
|
||||
return Group(
|
||||
name: json['name'],
|
||||
subtitle: json['subtitle'],
|
||||
photo: json['photo'],
|
||||
isGroup: json['isGroup'],
|
||||
members: json['members'],
|
||||
);
|
||||
}
|
||||
|
||||
static Map<String, dynamic> toJson(Group group) {
|
||||
return {
|
||||
'name': group.name,
|
||||
'subtitle': group.subtitle,
|
||||
'photo': group.photo,
|
||||
'isGroup': true,
|
||||
'members': group.members,
|
||||
};
|
||||
}
|
||||
|
||||
static String encode(List<Group> groups) => json.encode(
|
||||
groups
|
||||
.map<Map<String, dynamic>>((group) => Group.toJson(group))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
static List<Group> decode(String groups) =>
|
||||
(json.decode(groups) as List<dynamic>)
|
||||
.map<Group>((item) => Group.fromJson(item))
|
||||
.toList();
|
||||
}
|
||||
12
packages/simplex_app/lib/providers/drawer_providers.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class DrawerProvider extends ChangeNotifier {
|
||||
int _currentIndex = 1;
|
||||
|
||||
int get currentIndex => _currentIndex;
|
||||
|
||||
set currentIndex(int value) {
|
||||
_currentIndex = value;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
180
packages/simplex_app/lib/views/contacts/add_contact_view.dart
Normal file
@@ -0,0 +1,180 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:qr_code_scanner/qr_code_scanner.dart';
|
||||
|
||||
class AddContactView extends StatefulWidget {
|
||||
const AddContactView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_AddContactViewState createState() => _AddContactViewState();
|
||||
}
|
||||
|
||||
class _AddContactViewState extends State<AddContactView> {
|
||||
bool? _dontShow = false;
|
||||
final qrKey = GlobalKey(debugLabel: 'qr');
|
||||
QRViewController? _qrViewController;
|
||||
Barcode? result;
|
||||
|
||||
// alert dialgoue
|
||||
void _initialWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => StatefulBuilder(
|
||||
builder: (context, setState) => AlertDialog(
|
||||
title: const Text('Are you Sure?'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('Your profile will be sent to your contact!'),
|
||||
const SizedBox(height: 15.0),
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: _dontShow,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_dontShow = value;
|
||||
});
|
||||
}),
|
||||
const Text("Don't ask again")
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
InkWell(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(Icons.check, color: Colors.green),
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(Icons.cancel_outlined, color: Colors.red),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _intiBox() {
|
||||
Future.delayed(const Duration(seconds: 1), _initialWarning);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_intiBox();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_qrViewController?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Add Contact'),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: FutureBuilder(
|
||||
future: _qrViewController?.getFlashStatus(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Icon(snapshot.data == false
|
||||
? Icons.flash_on
|
||||
: Icons.flash_off);
|
||||
}
|
||||
return const Icon(Icons.flash_off);
|
||||
},
|
||||
),
|
||||
onPressed: () async {
|
||||
await _qrViewController?.toggleFlash();
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: FutureBuilder(
|
||||
future: _qrViewController?.getCameraInfo(),
|
||||
builder: (context, snapshot) {
|
||||
return const Icon(Icons.camera_alt);
|
||||
},
|
||||
),
|
||||
onPressed: () async {
|
||||
await _qrViewController?.flipCamera();
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SizedBox(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
child: Stack(
|
||||
children: [
|
||||
Center(
|
||||
child: GestureDetector(
|
||||
onTap: () => Navigator.of(context).pop(true),
|
||||
child: _qrViewBuild()),
|
||||
),
|
||||
const Center(
|
||||
child: Text(
|
||||
'Tap Here!',
|
||||
style:
|
||||
TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: MediaQuery.of(context).size.height * 0.15,
|
||||
left: MediaQuery.of(context).size.width * 0.125,
|
||||
child: const Text(
|
||||
'Position QR Code within the frame.',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 18.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
QRView _qrViewBuild() {
|
||||
var scanArea = (MediaQuery.of(context).size.width < 400 ||
|
||||
MediaQuery.of(context).size.height < 400)
|
||||
? 220.0
|
||||
: 370.0;
|
||||
|
||||
return QRView(
|
||||
key: qrKey,
|
||||
onQRViewCreated: (QRViewController controller) {
|
||||
_qrViewController = controller;
|
||||
controller.scannedDataStream.listen((scanData) {
|
||||
setState(() async {
|
||||
result = scanData;
|
||||
await controller.stopCamera();
|
||||
if (result != null) {
|
||||
Navigator.of(context).pop(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
overlay: QrScannerOverlayShape(
|
||||
borderColor: Colors.red,
|
||||
borderRadius: 0,
|
||||
borderLength: 50,
|
||||
borderWidth: 10,
|
||||
cutOutSize: scanArea,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
113
packages/simplex_app/lib/views/contacts/add_contact_web.dart
Normal file
@@ -0,0 +1,113 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:qr_code_scanner/qr_code_scanner.dart';
|
||||
|
||||
class AddContactWeb extends StatefulWidget {
|
||||
const AddContactWeb({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_AddContactWebState createState() => _AddContactWebState();
|
||||
}
|
||||
|
||||
class _AddContactWebState extends State<AddContactWeb> {
|
||||
bool? _dontShow = false;
|
||||
|
||||
// alert dialgoue
|
||||
void _initialWarning() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => StatefulBuilder(
|
||||
builder: (context, setState) => AlertDialog(
|
||||
title: const Text('Are you Sure?'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('Your profile will be sent to your contact!'),
|
||||
const SizedBox(height: 15.0),
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: _dontShow,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_dontShow = value;
|
||||
});
|
||||
}),
|
||||
const Text("Don't ask again")
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
InkWell(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(Icons.check, color: Colors.green),
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(Icons.cancel_outlined, color: Colors.red),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _intiBox() {
|
||||
Future.delayed(const Duration(seconds: 1), _initialWarning);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_intiBox();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: AppBar(
|
||||
title: const Text('Add Contact'),
|
||||
),
|
||||
body: SizedBox(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
child: Stack(
|
||||
children: [
|
||||
Center(
|
||||
child: GestureDetector(
|
||||
onTap: () => Navigator.of(context).pop(true),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border.all(
|
||||
color: Colors.red,
|
||||
width: 5.0,
|
||||
),
|
||||
),
|
||||
child: Image.asset('assets/code.png')),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: MediaQuery.of(context).size.height * 0.15,
|
||||
left: MediaQuery.of(context).size.width * 0.41,
|
||||
child: const Text(
|
||||
'Position QR Code within the frame.',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 18.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
482
packages/simplex_app/lib/views/contacts/conversations.dart
Normal file
@@ -0,0 +1,482 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:simplex_chat/animations/bottom_animation.dart';
|
||||
import 'package:simplex_chat/app_routes.dart';
|
||||
import 'package:simplex_chat/constants.dart';
|
||||
import 'package:simplex_chat/model/contact.dart';
|
||||
import 'package:simplex_chat/model/group.dart';
|
||||
import 'package:simplex_chat/views/conversation/conversation_view.dart';
|
||||
|
||||
class Conversations extends StatefulWidget {
|
||||
const Conversations({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ConversationsState createState() => _ConversationsState();
|
||||
}
|
||||
|
||||
class _ConversationsState extends State<Conversations> {
|
||||
bool? _eraseMedia = false;
|
||||
|
||||
List<dynamic> _conversations = [];
|
||||
|
||||
List<Contact> _contactsList = []; // for storing contacts
|
||||
List<Group> _groupList = []; // for storing groups
|
||||
|
||||
final List<String> _options = [
|
||||
'Add contact',
|
||||
'Scan invitation',
|
||||
'Add group',
|
||||
];
|
||||
|
||||
// getting data from local storage FOR NOW!!
|
||||
void _getContacts() async {
|
||||
debugPrint('Getting contacts!');
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final String? _contacts = prefs.getString('contacts');
|
||||
if (_contacts != null) {
|
||||
setState(() {
|
||||
_contactsList = List.from(Contact.decode(_contacts));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// getting data from local storage FOR NOW!!
|
||||
void _getGroups() async {
|
||||
debugPrint('Getting groups!');
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final String? _groups = prefs.getString('groups');
|
||||
if (_groups != null) {
|
||||
setState(() {
|
||||
_groupList = List.from(Group.decode(_groups));
|
||||
});
|
||||
}
|
||||
|
||||
_gettingGroupContactsChats();
|
||||
}
|
||||
|
||||
void _gettingGroupContactsChats() {
|
||||
debugPrint('Merging!');
|
||||
setState(() {
|
||||
_conversations = List.from(_contactsList);
|
||||
_conversations = _conversations + _groupList;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_getContacts();
|
||||
_getGroups();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0.0,
|
||||
backgroundColor: Colors.transparent,
|
||||
leadingWidth: 30,
|
||||
title: InkWell(
|
||||
onTap: _addNewContacts,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(
|
||||
Icons.bug_report,
|
||||
color: Colors.grey,
|
||||
size: 22.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
backgroundColor: Colors.white,
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 10.0),
|
||||
_contactsList.isEmpty
|
||||
? SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.7,
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: const [
|
||||
Text(
|
||||
"You don't have any conversation yet!",
|
||||
style: kMediumHeadingStyle,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 8.0),
|
||||
Text(
|
||||
'Click the icon below to add a contact',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: ListView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
children: List.generate(
|
||||
_conversations.length,
|
||||
(index) => WidgetAnimator(
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundImage:
|
||||
// ignore: avoid_dynamic_calls
|
||||
_conversations[index].photo == ''
|
||||
? const AssetImage('assets/dp.png')
|
||||
as ImageProvider
|
||||
: FileImage(
|
||||
// ignore: avoid_dynamic_calls
|
||||
File(_conversations[index].photo ??
|
||||
'')),
|
||||
),
|
||||
// ignore: avoid_dynamic_calls
|
||||
title: Text(_conversations[index].name ?? ''),
|
||||
subtitle:
|
||||
// ignore: avoid_dynamic_calls
|
||||
Text(_conversations[index].subtitle ?? ''),
|
||||
// ignore: avoid_dynamic_calls
|
||||
trailing: Icon(
|
||||
// ignore: avoid_dynamic_calls
|
||||
_conversations[index].isGroup
|
||||
? Icons.group
|
||||
: Icons.person,
|
||||
size: 18,
|
||||
color: Colors.grey[400],
|
||||
),
|
||||
onTap: () async {
|
||||
var value = await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => ConversationView(
|
||||
data: _conversations[index],
|
||||
),
|
||||
),
|
||||
);
|
||||
value ??= false;
|
||||
if (value) {
|
||||
_getContacts();
|
||||
_getGroups();
|
||||
}
|
||||
},
|
||||
onLongPress: () =>
|
||||
_conversationOptions(_conversations[index]),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: PopupMenuButton(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
),
|
||||
offset: const Offset(-10, -155),
|
||||
onSelected: (value) async {
|
||||
if (value == _options[0]) {
|
||||
var newMember =
|
||||
await Navigator.pushNamed(context, AppRoutes.scanInvitation);
|
||||
newMember ??= false;
|
||||
if (newMember == true) {
|
||||
_addNewMember();
|
||||
}
|
||||
} else if (value == _options[1]) {
|
||||
var newMember = await Navigator.pushNamed(context,
|
||||
kIsWeb ? AppRoutes.addContactWeb : AppRoutes.addContact);
|
||||
newMember ??= false;
|
||||
if (newMember == true) {
|
||||
_addNewMember();
|
||||
}
|
||||
} else {
|
||||
var newGroup =
|
||||
await Navigator.pushNamed(context, AppRoutes.addGroup);
|
||||
if (newGroup == true) {
|
||||
_getGroups();
|
||||
}
|
||||
}
|
||||
},
|
||||
itemBuilder: (context) => _options
|
||||
.map(
|
||||
(opt) => PopupMenuItem(
|
||||
value: opt,
|
||||
child: Text(opt),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
child: const FloatingActionButton(
|
||||
heroTag: 'connect',
|
||||
onPressed: null,
|
||||
child: Icon(
|
||||
Icons.person_add,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// delete a contact
|
||||
void _deleteContact(Contact contact) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
setState(() {
|
||||
_contactsList.remove(contact);
|
||||
});
|
||||
await prefs.setString('contacts', Contact.encode(_contactsList));
|
||||
var snackBar = SnackBar(
|
||||
backgroundColor: Colors.red,
|
||||
content: Text('${contact.name} deleted!'),
|
||||
);
|
||||
ScaffoldMessenger.of(context)
|
||||
..hideCurrentSnackBar()
|
||||
..showSnackBar(snackBar);
|
||||
}
|
||||
|
||||
// delete a group
|
||||
void _deleteGroup(Group group) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
setState(() {
|
||||
_groupList.remove(group);
|
||||
});
|
||||
await prefs.setString('groups', Group.encode(_groupList));
|
||||
var snackBar = SnackBar(
|
||||
backgroundColor: Colors.red,
|
||||
content: Text('${group.name} deleted!'),
|
||||
);
|
||||
ScaffoldMessenger.of(context)
|
||||
..hideCurrentSnackBar()
|
||||
..showSnackBar(snackBar);
|
||||
}
|
||||
|
||||
void _conversationOptions(var chat) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
_deleteConversation(chat);
|
||||
},
|
||||
child: const Text(
|
||||
'Delete Conversation',
|
||||
style: TextStyle(color: Colors.red),
|
||||
)),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
_disconnect();
|
||||
},
|
||||
child: const Text('Disconnect')),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _deleteConversation(var chat) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => StatefulBuilder(
|
||||
builder: (context, setState) => AlertDialog(
|
||||
title: const Text('Are you Sure?'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(
|
||||
'All conversation history will be deleted from your device!'),
|
||||
const SizedBox(height: 15.0),
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: _eraseMedia,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_eraseMedia = value;
|
||||
});
|
||||
}),
|
||||
const Text('Erase files & Media')
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
InkWell(
|
||||
// ignore: avoid_dynamic_calls
|
||||
onTap: chat.isGroup
|
||||
? () {
|
||||
_deleteGroup(chat);
|
||||
_conversations.remove(chat);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
: () {
|
||||
_deleteContact(chat);
|
||||
_conversations.remove(chat);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(Icons.check, color: Colors.green),
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(Icons.cancel_outlined, color: Colors.red),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _disconnect() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => StatefulBuilder(
|
||||
builder: (context, setState) => AlertDialog(
|
||||
title: const Text('Are you Sure?'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(
|
||||
'Disconnecting will erase all the data from your device and you will no longer be able to contact again!'),
|
||||
const SizedBox(height: 15.0),
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: _eraseMedia,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_eraseMedia = value;
|
||||
});
|
||||
}),
|
||||
const Text('Erase files & Media')
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
InkWell(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(Icons.check, color: Colors.green),
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(Icons.cancel_outlined, color: Colors.red),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// dummy ftn for loading new contacts
|
||||
void _addNewContacts() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
|
||||
// adding dummy contact
|
||||
List<Contact> _localList = [];
|
||||
final String? _local = prefs.getString('contacts');
|
||||
if (_local != null) {
|
||||
_localList = List.from(Contact.decode(_local));
|
||||
}
|
||||
|
||||
List<Contact> _newList = [
|
||||
Contact(
|
||||
name: 'Harry',
|
||||
subtitle: 'Hello!',
|
||||
),
|
||||
];
|
||||
_newList = _localList + _newList;
|
||||
|
||||
// dummy ftn for filling the list
|
||||
final String _newContacts = Contact.encode(_newList);
|
||||
|
||||
await prefs.setString('contacts', _newContacts);
|
||||
|
||||
// adding dummy contact
|
||||
List<Group> _localListGroup = [];
|
||||
final String? _localGroups = prefs.getString('groups');
|
||||
if (_local != null) {
|
||||
_localListGroup = List.from(Group.decode(_localGroups!));
|
||||
}
|
||||
|
||||
List<Group> _newGroups = [
|
||||
Group(
|
||||
name: 'College Friends',
|
||||
subtitle: 'Lovely people',
|
||||
members: ['Alice', 'James', 'Rio']),
|
||||
];
|
||||
_newGroups = _localListGroup + _newGroups;
|
||||
|
||||
// dummy ftn for filling the list
|
||||
final String _newGroup = Group.encode(_newGroups);
|
||||
|
||||
await prefs.setString('groups', _newGroup);
|
||||
|
||||
_getContacts();
|
||||
_getGroups();
|
||||
|
||||
const snackBar = SnackBar(
|
||||
backgroundColor: Colors.green,
|
||||
content: Text('New contacts loaded!'),
|
||||
);
|
||||
ScaffoldMessenger.of(context)
|
||||
..hideCurrentSnackBar()
|
||||
..showSnackBar(snackBar);
|
||||
}
|
||||
|
||||
void _addNewMember() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
// adding dummy contact
|
||||
List<Contact> _localList = [];
|
||||
final String? _local = prefs.getString('contacts');
|
||||
if (_local != null) {
|
||||
_localList = List.from(Contact.decode(_local));
|
||||
}
|
||||
|
||||
List<Contact> _newList = [
|
||||
Contact(
|
||||
name: 'Bob',
|
||||
subtitle: 'You and Bob are connected now!',
|
||||
),
|
||||
];
|
||||
_newList = _localList + _newList;
|
||||
|
||||
// dummy ftn for filling the list
|
||||
final String _newContacts = Contact.encode(_newList);
|
||||
|
||||
await prefs.setString('contacts', _newContacts);
|
||||
|
||||
_getContacts();
|
||||
_getGroups();
|
||||
|
||||
const snackBar = SnackBar(
|
||||
backgroundColor: Colors.green,
|
||||
content: Text('New connection added!'),
|
||||
);
|
||||
ScaffoldMessenger.of(context)
|
||||
..hideCurrentSnackBar()
|
||||
..showSnackBar(snackBar);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:simplex_chat/constants.dart';
|
||||
import 'package:simplex_chat/model/contact.dart';
|
||||
|
||||
class ContactDetailsConversation extends StatelessWidget {
|
||||
final Contact contact;
|
||||
const ContactDetailsConversation({Key? key, required this.contact})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
title: Text(contact.name!),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 12.0),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const CircleAvatar(
|
||||
radius: 65,
|
||||
backgroundImage: AssetImage('assets/dp.png'),
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
const Text('Display Name', style: kMediumHeadingStyle),
|
||||
Text(contact.name!),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:simplex_chat/views/conversation/contact_detail_conversation.dart';
|
||||
import 'package:simplex_chat/views/conversation/group_detail_conversation.dart';
|
||||
import 'package:simplex_chat/widgets/message_bubble.dart';
|
||||
|
||||
/// View the details of group by tapping the [appBar]
|
||||
/// Viwe the details of chat by tapping the [appBar]
|
||||
/// Generate [Fake Messages] by tapping the [Message Icon]
|
||||
|
||||
class ConversationView extends StatefulWidget {
|
||||
// ignore: prefer_typing_uninitialized_variables
|
||||
final data;
|
||||
const ConversationView({Key? key, this.data}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ConversationViewState createState() => _ConversationViewState();
|
||||
}
|
||||
|
||||
class _ConversationViewState extends State<ConversationView> {
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
final TextEditingController _messageFieldController = TextEditingController();
|
||||
|
||||
FocusNode? _focus;
|
||||
bool _fieldEnabled = false;
|
||||
final List<Widget> _chatMessages = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_focus = FocusNode();
|
||||
_focus!.addListener(() {
|
||||
debugPrint('FOCUS ${_focus!.hasFocus}');
|
||||
_fieldEnabled = _focus!.hasFocus;
|
||||
debugPrint('MESSAGE ENABLED $_fieldEnabled');
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_messageFieldController.dispose();
|
||||
_scrollController.dispose();
|
||||
_focus!.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => FocusScope.of(context).unfocus(),
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: BackButton(
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
),
|
||||
leadingWidth: MediaQuery.of(context).size.width * 0.085,
|
||||
title: InkWell(
|
||||
// ignore: avoid_dynamic_calls
|
||||
onTap: widget.data.isGroup
|
||||
? () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => GroupDetailsConversation(
|
||||
group: widget.data,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => ContactDetailsConversation(
|
||||
contact: widget.data,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 15,
|
||||
// ignore: avoid_dynamic_calls
|
||||
backgroundImage: widget.data.photo == ''
|
||||
? const AssetImage('assets/dp.png') as ImageProvider
|
||||
: FileImage(
|
||||
// ignore: avoid_dynamic_calls
|
||||
File(widget.data.photo),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10.0),
|
||||
Text(
|
||||
// ignore: avoid_dynamic_calls
|
||||
widget.data.name,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_chatMessages.add(MessageBubble(
|
||||
isUser: false,
|
||||
// ignore: avoid_dynamic_calls
|
||||
sender: widget.data.isGroup
|
||||
// ignore: avoid_dynamic_calls
|
||||
? widget.data.members.length == 0
|
||||
? 'some person'
|
||||
// ignore: avoid_dynamic_calls
|
||||
: widget.data.members[0]
|
||||
// ignore: avoid_dynamic_calls
|
||||
: widget.data.name,
|
||||
text: 'Hey there! How is it going?',
|
||||
));
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.bug_report,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: _chatMessages.isEmpty
|
||||
? const Center(
|
||||
child: Text('Send a message to get started'),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: _chatMessages,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(width: 10.0),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 45.0,
|
||||
child: TextFormField(
|
||||
maxLines: null,
|
||||
focusNode: _focus,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
keyboardType: TextInputType.multiline,
|
||||
textInputAction: TextInputAction.newline,
|
||||
controller: _messageFieldController,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 10.0,
|
||||
),
|
||||
hintText: 'Message...',
|
||||
hintStyle: Theme.of(context).textTheme.caption,
|
||||
fillColor: Colors.grey[200],
|
||||
filled: true,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(360),
|
||||
borderSide:
|
||||
const BorderSide(color: Colors.transparent),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(360),
|
||||
borderSide:
|
||||
const BorderSide(color: Colors.transparent),
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
if (_messageFieldController.text.isNotEmpty) {
|
||||
setState(() {
|
||||
_chatMessages.add(MessageBubble(
|
||||
isUser: true,
|
||||
sender: 'You',
|
||||
text: _messageFieldController.text.trim(),
|
||||
));
|
||||
});
|
||||
_messageFieldController.clear();
|
||||
_focus!.unfocus();
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.send_rounded,
|
||||
size: 25.0, color: Colors.teal),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.02,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:simplex_chat/constants.dart';
|
||||
import 'package:simplex_chat/model/contact.dart';
|
||||
import 'package:simplex_chat/model/group.dart';
|
||||
|
||||
enum MemberSetting { owner, admin, member }
|
||||
|
||||
class GroupDetailsConversation extends StatefulWidget {
|
||||
final Group group;
|
||||
const GroupDetailsConversation({Key? key, required this.group})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_GroupDetailsConversationState createState() =>
|
||||
_GroupDetailsConversationState();
|
||||
}
|
||||
|
||||
class _GroupDetailsConversationState extends State<GroupDetailsConversation> {
|
||||
MemberSetting _memberSetting = MemberSetting.member;
|
||||
|
||||
bool _addMember = false;
|
||||
List<Contact> _contactsList = []; // for storing contacts
|
||||
List _newMembers = [];
|
||||
|
||||
List<Group> _groupList = [];
|
||||
List _members = [];
|
||||
|
||||
// getting all members of group
|
||||
void _getMembers() {
|
||||
setState(() {
|
||||
_members = List.from(widget.group.members!);
|
||||
});
|
||||
}
|
||||
|
||||
// getting groups
|
||||
void _getGroups() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final String? _groups = prefs.getString('groups');
|
||||
if (_groups != null) {
|
||||
setState(() {
|
||||
_groupList = List.from(Group.decode(_groups));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// getting data from local storage FOR NOW
|
||||
void _getContacts() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final String? _contacts = prefs.getString('contacts');
|
||||
setState(() {
|
||||
_contactsList = List.from(Contact.decode(_contacts!));
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_getContacts();
|
||||
_getGroups();
|
||||
_getMembers();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
title: Text(widget.group.name!),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 12.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Center(
|
||||
child: CircleAvatar(
|
||||
radius: 70,
|
||||
backgroundImage: widget.group.photo == ''
|
||||
? const AssetImage('assets/dp.png') as ImageProvider
|
||||
: FileImage(File(widget.group.photo!)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 25.0),
|
||||
const Text('Group Name', style: kMediumHeadingStyle),
|
||||
Text(widget.group.name!),
|
||||
const Divider(),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.person_add),
|
||||
title: const Text('Add a member'),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_addMember = !_addMember;
|
||||
});
|
||||
},
|
||||
),
|
||||
const Divider(),
|
||||
_newMembers.isNotEmpty
|
||||
? const Text('New Members Added')
|
||||
: Container(),
|
||||
SizedBox(height: _newMembers.isNotEmpty ? 10.0 : 0.0),
|
||||
_newMembers.isNotEmpty
|
||||
? SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: List.generate(
|
||||
_newMembers.length,
|
||||
(index) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5.0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_newMembers.remove(_newMembers[index]);
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(7.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
color: Colors.grey.withAlpha(100)),
|
||||
child: Text(_newMembers[index]),
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
)
|
||||
: Container(),
|
||||
SizedBox(height: _addMember ? 10.0 : 0.0),
|
||||
_addMember ? const Text('Contacts Available') : Container(),
|
||||
SizedBox(height: _addMember ? 10.0 : 0.0),
|
||||
_addMember
|
||||
? ListView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
children: List.generate(
|
||||
_contactsList.length,
|
||||
(index) => ListTile(
|
||||
leading: const CircleAvatar(
|
||||
backgroundImage: AssetImage('assets/dp.png'),
|
||||
),
|
||||
title: Text(_contactsList[index].name!),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_newMembers.add(_contactsList[index].name);
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
SizedBox(height: _addMember ? 10.0 : 0.0),
|
||||
const Text('Members', style: kMediumHeadingStyle),
|
||||
const SizedBox(height: 5.0),
|
||||
for (int i = 0; i < _members.length; i++)
|
||||
ListTile(
|
||||
leading: const CircleAvatar(
|
||||
backgroundImage: AssetImage('assets/dp.png'),
|
||||
),
|
||||
title: Text(_members[i]),
|
||||
trailing: InkWell(
|
||||
onTap: () => _memberSettings(_members[i]),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(Icons.settings),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: _newMembers.isEmpty
|
||||
? Container()
|
||||
: FloatingActionButton(
|
||||
onPressed: _addNewMembers,
|
||||
child: const Icon(Icons.check),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _memberSettings(String contact) {
|
||||
Size _size = MediaQuery.of(context).size;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => StatefulBuilder(
|
||||
builder: (context, setState) => AlertDialog(
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(width: _size.width * 0.15),
|
||||
const Expanded(child: Text('Owner')),
|
||||
Radio(
|
||||
value: MemberSetting.owner,
|
||||
groupValue: _memberSetting,
|
||||
onChanged: (MemberSetting? value) {
|
||||
setState(() {
|
||||
_memberSetting = value!;
|
||||
});
|
||||
}),
|
||||
SizedBox(width: _size.width * 0.15),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(width: _size.width * 0.15),
|
||||
const Expanded(child: Text('Admin')),
|
||||
Radio(
|
||||
groupValue: _memberSetting,
|
||||
value: MemberSetting.admin,
|
||||
onChanged: (MemberSetting? value) {
|
||||
setState(() {
|
||||
_memberSetting = value!;
|
||||
});
|
||||
}),
|
||||
SizedBox(width: _size.width * 0.15),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(width: _size.width * 0.15),
|
||||
const Expanded(child: Text('Member')),
|
||||
Radio(
|
||||
groupValue: _memberSetting,
|
||||
value: MemberSetting.member,
|
||||
onChanged: (MemberSetting? value) {
|
||||
setState(() {
|
||||
_memberSetting = value!;
|
||||
});
|
||||
}),
|
||||
SizedBox(width: _size.width * 0.15),
|
||||
],
|
||||
),
|
||||
const Divider(),
|
||||
TextButton(
|
||||
onPressed: () => _removeMember(contact),
|
||||
child: const Text('Remove from group',
|
||||
style: TextStyle(color: Colors.red)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _addNewMembers() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
// add new members to the _members list
|
||||
setState(() {
|
||||
_members = _members + _newMembers;
|
||||
_newMembers = [];
|
||||
_addMember = false;
|
||||
});
|
||||
|
||||
const snackBar = SnackBar(
|
||||
backgroundColor: Colors.green, content: Text('New members added!'));
|
||||
ScaffoldMessenger.of(context)
|
||||
..hideCurrentSnackBar()
|
||||
..showSnackBar(snackBar);
|
||||
|
||||
// get index of group in local
|
||||
int index = 0;
|
||||
|
||||
index = _groupList.indexWhere((group) => group.name == widget.group.name);
|
||||
|
||||
// add the full _members list to the group
|
||||
Group _updatedGroup = Group(
|
||||
name: widget.group.name,
|
||||
subtitle: widget.group.subtitle,
|
||||
members: _members,
|
||||
photo: widget.group.photo,
|
||||
);
|
||||
|
||||
// put it in updated group local list
|
||||
_groupList[index] = _updatedGroup;
|
||||
|
||||
// convert to string
|
||||
final String _updatedGroupString = Group.encode(_groupList);
|
||||
|
||||
// update the group in local storage
|
||||
await prefs.setString('groups', _updatedGroupString);
|
||||
}
|
||||
|
||||
void _removeMember(String contact) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
|
||||
Navigator.pop(context);
|
||||
|
||||
// remove the current member
|
||||
setState(() {
|
||||
_members.remove(contact);
|
||||
});
|
||||
|
||||
var snackBar = SnackBar(
|
||||
backgroundColor: Colors.red, content: Text('$contact removed!'));
|
||||
ScaffoldMessenger.of(context)
|
||||
..hideCurrentSnackBar()
|
||||
..showSnackBar(snackBar);
|
||||
|
||||
// get index of group in local
|
||||
int index = 0;
|
||||
|
||||
index = _groupList.indexWhere((group) => group.name == widget.group.name);
|
||||
|
||||
// new instance of group (updated)
|
||||
Group _updatedGroup = Group(
|
||||
name: widget.group.name,
|
||||
subtitle: widget.group.subtitle,
|
||||
photo: widget.group.photo,
|
||||
members: _members,
|
||||
);
|
||||
|
||||
// put it in group local list
|
||||
_groupList[index] = _updatedGroup;
|
||||
|
||||
// convert to string
|
||||
final String _updatedGroupString = Group.encode(_groupList);
|
||||
|
||||
// update the group in local storage
|
||||
await prefs.setString('groups', _updatedGroupString);
|
||||
}
|
||||
}
|
||||
432
packages/simplex_app/lib/views/group/add_group_view.dart
Normal file
@@ -0,0 +1,432 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:simplex_chat/constants.dart';
|
||||
import 'package:simplex_chat/model/contact.dart';
|
||||
import 'package:simplex_chat/model/group.dart';
|
||||
import 'package:simplex_chat/widgets/custom_text_field.dart';
|
||||
|
||||
class AddGroupView extends StatefulWidget {
|
||||
const AddGroupView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_AddGroupViewState createState() => _AddGroupViewState();
|
||||
}
|
||||
|
||||
class _AddGroupViewState extends State<AddGroupView> {
|
||||
// Image Picker --> DP properties
|
||||
final imgPicker = ImagePicker();
|
||||
File? image;
|
||||
String _groupPhotoPath = '';
|
||||
bool _uploading = false;
|
||||
bool _imageUploaded = false;
|
||||
|
||||
final List _members = [];
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final _displayNameController = TextEditingController();
|
||||
final _descController = TextEditingController();
|
||||
|
||||
bool _addMember = false;
|
||||
List<Contact> _contactsList = []; // for storing contacts
|
||||
|
||||
// image buttons options
|
||||
final _dpBtnText = ['Remove', 'Gallery', 'Camera'];
|
||||
final _dpBtnColors = [Colors.red, Colors.purple, Colors.green];
|
||||
final _dpBtnIcons = [
|
||||
Icons.delete,
|
||||
Icons.photo_rounded,
|
||||
Icons.camera_alt_rounded
|
||||
];
|
||||
|
||||
// getting data from local storage FOR NOW
|
||||
void _getContacts() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final String? _contacts = prefs.getString('contacts');
|
||||
setState(() {
|
||||
_contactsList = List.from(Contact.decode(_contacts!));
|
||||
});
|
||||
}
|
||||
|
||||
String _userPhotoPath = '';
|
||||
void _getUserPhoto() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
String? _photo = prefs.getString('photo${prefs.getString('displayName')}');
|
||||
if (_photo != null) {
|
||||
setState(() {
|
||||
_userPhotoPath = _photo;
|
||||
});
|
||||
}
|
||||
debugPrint(_userPhotoPath);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_getUserPhoto();
|
||||
_getContacts();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_displayNameController.dispose();
|
||||
_descController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Size _size = MediaQuery.of(context).size;
|
||||
return GestureDetector(
|
||||
onTap: () => FocusScope.of(context).unfocus(),
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: BackButton(
|
||||
onPressed: () => Navigator.of(context).pop(false),
|
||||
),
|
||||
title: const Text('New Group'),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SizedBox(height: _size.height * 0.012),
|
||||
Center(
|
||||
child: SizedBox(
|
||||
height: 180.0,
|
||||
width: 180.0,
|
||||
child: Stack(
|
||||
children: [
|
||||
_imageUploaded
|
||||
? CircleAvatar(
|
||||
radius: _size.height * 0.12,
|
||||
backgroundImage:
|
||||
FileImage(File(_groupPhotoPath)),
|
||||
)
|
||||
: CircleAvatar(
|
||||
radius: _size.height * 0.12,
|
||||
backgroundImage:
|
||||
const AssetImage('assets/dp.png'),
|
||||
),
|
||||
Positioned(
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: FloatingActionButton(
|
||||
backgroundColor: kSecondaryColor,
|
||||
elevation: 2.0,
|
||||
mini: true,
|
||||
onPressed: _updateProfilePic,
|
||||
child: _uploading
|
||||
? const SizedBox(
|
||||
height: 18.0,
|
||||
width: 18.0,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2.0,
|
||||
valueColor:
|
||||
AlwaysStoppedAnimation<Color>(
|
||||
Colors.white),
|
||||
),
|
||||
)
|
||||
: const Icon(
|
||||
Icons.add_a_photo,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: _size.height * 0.03),
|
||||
const Text('Group Name', style: kSmallHeadingStyle),
|
||||
SizedBox(height: _size.height * 0.012),
|
||||
CustomTextField(
|
||||
textEditingController: _displayNameController,
|
||||
textInputType: TextInputType.name,
|
||||
hintText: 'e.g College friends',
|
||||
validatorFtn: (String? value) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Group name cannot be empty';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
SizedBox(height: _size.height * 0.012),
|
||||
const Text('Group Description', style: kSmallHeadingStyle),
|
||||
SizedBox(height: _size.height * 0.012),
|
||||
CustomTextField(
|
||||
textEditingController: _descController,
|
||||
textInputType: TextInputType.text,
|
||||
hintText: 'e.g Friends from UK',
|
||||
),
|
||||
SizedBox(height: _size.height * 0.012),
|
||||
_members.isNotEmpty
|
||||
? const Text('Members Added')
|
||||
: Container(),
|
||||
SizedBox(height: _members.isNotEmpty ? 10.0 : 0.0),
|
||||
_members.isNotEmpty
|
||||
? SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: List.generate(
|
||||
_members.length,
|
||||
(index) => Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 5.0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_members.remove(_members[index]);
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(7.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
color: Colors.grey.withAlpha(100)),
|
||||
child: Text(_members[index]),
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
)
|
||||
: Container(),
|
||||
SizedBox(
|
||||
height: _members.isNotEmpty ? _size.height * 0.012 : 0.0),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.person_add),
|
||||
title: const Text('Add a member'),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_addMember = !_addMember;
|
||||
});
|
||||
},
|
||||
),
|
||||
SizedBox(height: _addMember ? _size.height * 0.012 : 0.0),
|
||||
_addMember ? const Text('Contacts Available') : Container(),
|
||||
SizedBox(height: _addMember ? _size.height * 0.012 : 0.0),
|
||||
_addMember
|
||||
? ListView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
children: List.generate(
|
||||
_contactsList.length,
|
||||
(index) => ListTile(
|
||||
leading: const CircleAvatar(
|
||||
backgroundImage: AssetImage('assets/dp.png'),
|
||||
),
|
||||
title: Text(_contactsList[index].name!),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_members.add(_contactsList[index].name);
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
Divider(height: _size.height * 0.035),
|
||||
ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundImage: _userPhotoPath == ''
|
||||
? const AssetImage('assets/dp.png') as ImageProvider
|
||||
: FileImage(File(_userPhotoPath)),
|
||||
),
|
||||
title: const Text('You'),
|
||||
subtitle: const Text(
|
||||
'Owner',
|
||||
style: TextStyle(color: Colors.grey, fontSize: 12.0),
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: Visibility(
|
||||
visible: MediaQuery.of(context).viewInsets.bottom == 0,
|
||||
child: FloatingActionButton(
|
||||
heroTag: 'setup',
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
FocusScope.of(context).unfocus();
|
||||
_addNewGroup(_displayNameController.text.trim(),
|
||||
_descController.text.trim());
|
||||
_descController.clear();
|
||||
_displayNameController.clear();
|
||||
Navigator.of(context).pop(true);
|
||||
}
|
||||
},
|
||||
child: const Icon(Icons.check),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _updateProfilePic() {
|
||||
showModalBottomSheet(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(10.0),
|
||||
topRight: Radius.circular(10.0),
|
||||
),
|
||||
),
|
||||
context: context,
|
||||
builder: (context) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 20.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey,
|
||||
borderRadius: BorderRadius.circular(360.0)),
|
||||
height: 7.0,
|
||||
width: 50.0,
|
||||
),
|
||||
const SizedBox(height: 20.0),
|
||||
const Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
' Profile photo',
|
||||
style: kHeadingStyle,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
Row(
|
||||
children: List.generate(
|
||||
3,
|
||||
(index) => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
MaterialButton(
|
||||
color: _dpBtnColors.map((e) => e).elementAt(index),
|
||||
shape: const CircleBorder(),
|
||||
onPressed: index == 0
|
||||
? () => _removePic()
|
||||
: index == 1
|
||||
? () => _galleryPic()
|
||||
: () => _cameraPic(),
|
||||
child: Icon(
|
||||
_dpBtnIcons.map((e) => e).elementAt(index),
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
_dpBtnText.map((e) => e).elementAt(index),
|
||||
textAlign: TextAlign.center,
|
||||
)
|
||||
],
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _removePic() {
|
||||
setState(() {
|
||||
_imageUploaded = false;
|
||||
image = null;
|
||||
_groupPhotoPath = '';
|
||||
});
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
void _cameraPic() async {
|
||||
try {
|
||||
setState(() {
|
||||
_uploading = true;
|
||||
});
|
||||
|
||||
// picking Image from Camera
|
||||
final file = await imgPicker.getImage(
|
||||
source: ImageSource.camera,
|
||||
);
|
||||
|
||||
if (file != null) {
|
||||
image = File(file.path);
|
||||
setState(() {
|
||||
_uploading = false;
|
||||
_imageUploaded = true;
|
||||
_groupPhotoPath = file.path;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_uploading = false;
|
||||
});
|
||||
}
|
||||
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
void _galleryPic() async {
|
||||
try {
|
||||
setState(() {
|
||||
_uploading = true;
|
||||
});
|
||||
|
||||
// picking Image from local storage
|
||||
final file = await imgPicker.getImage(
|
||||
source: ImageSource.gallery,
|
||||
);
|
||||
|
||||
if (file != null) {
|
||||
image = File(file.path);
|
||||
setState(() {
|
||||
_uploading = false;
|
||||
_imageUploaded = true;
|
||||
_groupPhotoPath = file.path;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_uploading = false;
|
||||
});
|
||||
}
|
||||
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
void _addNewGroup(String name, String desc) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
List<Group> _localList = [];
|
||||
final String? _local = prefs.getString('groups');
|
||||
if (_local != null) {
|
||||
_localList = List.from(Group.decode(_local));
|
||||
}
|
||||
List<Group> _groups = [
|
||||
Group(
|
||||
name: name,
|
||||
photo: _groupPhotoPath,
|
||||
subtitle: desc,
|
||||
members: _members,
|
||||
),
|
||||
];
|
||||
debugPrint(_groups[0].isGroup.toString());
|
||||
_groups = _localList + _groups;
|
||||
|
||||
final String _newGroups = Group.encode(_groups);
|
||||
|
||||
await prefs.setString('groups', _newGroups);
|
||||
|
||||
var snackBar = SnackBar(
|
||||
backgroundColor: Colors.green,
|
||||
content: Text('$name added'),
|
||||
);
|
||||
ScaffoldMessenger.of(context)
|
||||
..hideCurrentSnackBar()
|
||||
..showSnackBar(snackBar);
|
||||
}
|
||||
}
|
||||
59
packages/simplex_app/lib/views/home/drawer.dart
Normal file
@@ -0,0 +1,59 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:simplex_chat/providers/drawer_providers.dart';
|
||||
|
||||
class MyDrawer extends StatelessWidget {
|
||||
const MyDrawer({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _drawerProviders = Provider.of<DrawerProvider>(context);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: Builder(builder: (context) {
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 30.0),
|
||||
SvgPicture.asset(
|
||||
'assets/logo.svg',
|
||||
height: 55.0,
|
||||
),
|
||||
const Divider(height: 30.0),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.insert_invitation),
|
||||
title: const Text('Invitations'),
|
||||
onTap: () {
|
||||
_drawerProviders.currentIndex = 2;
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
const Spacer(),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.refresh),
|
||||
title: const Text('Switch Profile'),
|
||||
subtitle: const Text(
|
||||
'Not supported yet!',
|
||||
style: TextStyle(fontStyle: FontStyle.italic),
|
||||
),
|
||||
onTap: () => _switchProfile(context),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// remove the locally stored user data
|
||||
void _switchProfile(BuildContext context) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
|
||||
int _count = 0;
|
||||
Navigator.of(context).popUntil((route) => _count++ >= 2);
|
||||
String? _name = prefs.getString('displayName');
|
||||
await prefs.remove('displayName');
|
||||
await prefs.remove('fullName');
|
||||
await prefs.remove('photo$_name');
|
||||
}
|
||||
}
|
||||
189
packages/simplex_app/lib/views/home/home_view.dart
Normal file
@@ -0,0 +1,189 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:simplex_chat/constants.dart';
|
||||
import 'package:simplex_chat/providers/drawer_providers.dart';
|
||||
import 'package:simplex_chat/views/contacts/conversations.dart';
|
||||
import 'package:simplex_chat/views/home/drawer.dart';
|
||||
import 'package:simplex_chat/views/invitations/invitation_view.dart';
|
||||
import 'package:simplex_chat/views/profile/profile_view.dart';
|
||||
|
||||
/// Generate [Fake Contacts] by tapping the [Bug Icon]
|
||||
|
||||
class HomeView extends StatefulWidget {
|
||||
const HomeView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_HomeViewState createState() => _HomeViewState();
|
||||
}
|
||||
|
||||
class _HomeViewState extends State<HomeView> {
|
||||
String? _photo = '';
|
||||
String? _displayName = '';
|
||||
|
||||
// views
|
||||
final List<Widget> _views = [
|
||||
const ProfileView(),
|
||||
const Conversations(),
|
||||
const Invitations(),
|
||||
];
|
||||
|
||||
void _getUserData() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
setState(() {
|
||||
_displayName = prefs.getString('displayName');
|
||||
_photo = prefs.getString('photo$_displayName');
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_getUserData();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _drawerProviders = Provider.of<DrawerProvider>(context);
|
||||
return WillPopScope(
|
||||
onWillPop: _onWillPop,
|
||||
child: Scaffold(
|
||||
drawer: const Drawer(child: MyDrawer()),
|
||||
body: SafeArea(
|
||||
child: Builder(builder: (context) {
|
||||
return Stack(
|
||||
children: [
|
||||
_views[_drawerProviders.currentIndex],
|
||||
_drawerProviders.currentIndex == 0
|
||||
? Positioned(
|
||||
top: MediaQuery.of(context).size.height * 0.017,
|
||||
left: MediaQuery.of(context).size.width * 0.02,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
_drawerProviders.currentIndex = 1;
|
||||
_getUserData();
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(Icons.arrow_back, color: kPrimaryColor),
|
||||
),
|
||||
),
|
||||
)
|
||||
: _drawerProviders.currentIndex == 2
|
||||
? Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
_drawerProviders.currentIndex = 1;
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(Icons.arrow_back,
|
||||
color: kPrimaryColor)),
|
||||
),
|
||||
const Spacer(),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text('Hi! $_displayName',
|
||||
style: kSmallHeadingStyle),
|
||||
const Text('Good day!'),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 10.0),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
_drawerProviders.currentIndex = 0;
|
||||
},
|
||||
child: CircleAvatar(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundImage: _photo!.isEmpty
|
||||
? const AssetImage('assets/dp.png')
|
||||
as ImageProvider
|
||||
: FileImage(File(_photo!)),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Scaffold.of(context).openDrawer();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SvgPicture.asset('assets/menu.svg'),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text('Hi! $_displayName',
|
||||
style: kSmallHeadingStyle),
|
||||
const Text('Good day!'),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 10.0),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
_drawerProviders.currentIndex = 0;
|
||||
},
|
||||
child: CircleAvatar(
|
||||
backgroundImage: _photo!.isEmpty
|
||||
? const AssetImage('assets/dp.png')
|
||||
as ImageProvider
|
||||
: FileImage(File(_photo!)),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> _onWillPop() async {
|
||||
return (await showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Exit Application', style: kMediumHeadingStyle),
|
||||
content: const Text('Are You Sure?'),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: const Text(
|
||||
'Yes',
|
||||
style: TextStyle(
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
onPressed: () => SystemNavigator.pop(),
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('No'),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
),
|
||||
)) ??
|
||||
false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:simplex_chat/constants.dart';
|
||||
|
||||
class Invitations extends StatefulWidget {
|
||||
const Invitations({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<Invitations> createState() => _InvitationsState();
|
||||
}
|
||||
|
||||
class _InvitationsState extends State<Invitations> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 40.0),
|
||||
Row(
|
||||
children: const [
|
||||
Icon(Icons.inventory_outlined, color: kPrimaryColor),
|
||||
SizedBox(width: 8.0),
|
||||
Text(
|
||||
'Invitations',
|
||||
style: kHeadingStyle,
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 5.0),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.7,
|
||||
child: const Center(
|
||||
child: Text(
|
||||
"You don't have any invitations yet!",
|
||||
style: kSmallHeadingStyle,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
41
packages/simplex_app/lib/views/onboarding/intro_view.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:simplex_chat/app_routes.dart';
|
||||
import 'package:simplex_chat/constants.dart';
|
||||
|
||||
class IntroView extends StatelessWidget {
|
||||
const IntroView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
'assets/logo.svg',
|
||||
height: 80.0,
|
||||
),
|
||||
SizedBox(height: MediaQuery.of(context).size.height * 0.05),
|
||||
const Text(
|
||||
'Complete your profile to begin using SimpleX. Your profile is local to your device and will help identify you to your connections.',
|
||||
style: kMediumHeadingStyle,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
heroTag: 'welcome',
|
||||
onPressed: () => Navigator.pushNamed(context, AppRoutes.setupProfile),
|
||||
child: const Icon(
|
||||
Icons.arrow_forward,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
320
packages/simplex_app/lib/views/profile/profile_view.dart
Normal file
@@ -0,0 +1,320 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:simplex_chat/constants.dart';
|
||||
import 'package:simplex_chat/widgets/custom_text_field.dart';
|
||||
|
||||
class ProfileView extends StatefulWidget {
|
||||
const ProfileView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ProfileViewState createState() => _ProfileViewState();
|
||||
}
|
||||
|
||||
class _ProfileViewState extends State<ProfileView> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
// controllers
|
||||
final TextEditingController _displayNameController = TextEditingController();
|
||||
final TextEditingController _fullNameController = TextEditingController();
|
||||
|
||||
// Image Picker --> DP properties
|
||||
final imgPicker = ImagePicker();
|
||||
File? image;
|
||||
String? _photo = '';
|
||||
bool _uploading = false;
|
||||
|
||||
// image buttons options
|
||||
final _dpBtnText = ['Remove', 'Gallery', 'Camera'];
|
||||
final _dpBtnColors = [Colors.red, Colors.purple, Colors.green];
|
||||
final _dpBtnIcons = [
|
||||
Icons.delete,
|
||||
Icons.photo_rounded,
|
||||
Icons.camera_alt_rounded
|
||||
];
|
||||
|
||||
String? _displayName = '';
|
||||
String? _fullName = '';
|
||||
|
||||
void _getUserData() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
setState(() {
|
||||
_fullName = prefs.getString('fullName');
|
||||
_displayName = prefs.getString('displayName');
|
||||
_photo = prefs.getString('photo$_displayName');
|
||||
});
|
||||
_displayNameController.text = _displayName!;
|
||||
if (_fullName != null) _fullNameController.text = _fullName!;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_getUserData();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_displayNameController.dispose();
|
||||
_fullNameController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Size _size = MediaQuery.of(context).size;
|
||||
return Scaffold(
|
||||
body: GestureDetector(
|
||||
onTap: () => FocusScope.of(context).unfocus(),
|
||||
child: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SizedBox(height: _size.height * 0.05),
|
||||
Center(
|
||||
child: SizedBox(
|
||||
height: 180.0,
|
||||
width: 180.0,
|
||||
child: Stack(
|
||||
children: [
|
||||
_photo != ''
|
||||
? CircleAvatar(
|
||||
backgroundColor: Colors.white,
|
||||
radius: 100.0,
|
||||
backgroundImage: FileImage(File(_photo!)),
|
||||
)
|
||||
: const CircleAvatar(
|
||||
backgroundColor: Colors.white,
|
||||
radius: 100.0,
|
||||
backgroundImage: AssetImage('assets/dp.png'),
|
||||
),
|
||||
Positioned(
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: FloatingActionButton(
|
||||
backgroundColor: kSecondaryColor,
|
||||
elevation: 2.0,
|
||||
mini: true,
|
||||
onPressed: _updateProfilePic,
|
||||
child: _uploading
|
||||
? const SizedBox(
|
||||
height: 18.0,
|
||||
width: 18.0,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2.0,
|
||||
valueColor:
|
||||
AlwaysStoppedAnimation<Color>(
|
||||
Colors.white),
|
||||
),
|
||||
)
|
||||
: const Icon(
|
||||
Icons.add_a_photo,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
SizedBox(height: _size.height * 0.035),
|
||||
const Text('Display Name', style: kSmallHeadingStyle),
|
||||
const SizedBox(height: 10.0),
|
||||
CustomTextField(
|
||||
textEditingController: _displayNameController,
|
||||
textInputType: TextInputType.name,
|
||||
hintText: 'e.g John',
|
||||
validatorFtn: (value) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Display name cannot be empty';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
SizedBox(height: _size.height * 0.035),
|
||||
const Text('Full Name', style: kSmallHeadingStyle),
|
||||
SizedBox(height: _size.height * 0.012),
|
||||
CustomTextField(
|
||||
textEditingController: _fullNameController,
|
||||
textInputType: TextInputType.name,
|
||||
hintText: 'e.g John Doe',
|
||||
),
|
||||
SizedBox(height: _size.height * 0.035),
|
||||
const Text(
|
||||
'Your display name is what your contact will know you :)',
|
||||
style: TextStyle(letterSpacing: 1.2),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
heroTag: 'save',
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
FocusManager.instance.primaryFocus!.unfocus();
|
||||
await _createProfile();
|
||||
const snackBar = SnackBar(
|
||||
backgroundColor: Colors.green,
|
||||
content: Text('Profile updated!'),
|
||||
);
|
||||
|
||||
ScaffoldMessenger.of(context)
|
||||
..hideCurrentSnackBar()
|
||||
..showSnackBar(snackBar);
|
||||
}
|
||||
},
|
||||
child: const Icon(Icons.check),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// create profile and store in local
|
||||
Future<void> _createProfile() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString('displayName', _displayNameController.text.trim());
|
||||
await prefs.setString('fullName', _fullNameController.text.trim());
|
||||
await prefs.setString(
|
||||
'photo${_displayNameController.text.trim()}', _photo!);
|
||||
|
||||
debugPrint(prefs.getString('photo'));
|
||||
}
|
||||
|
||||
void _updateProfilePic() {
|
||||
Size _size = MediaQuery.of(context).size;
|
||||
showModalBottomSheet(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(10.0),
|
||||
topRight: Radius.circular(10.0),
|
||||
),
|
||||
),
|
||||
context: context,
|
||||
builder: (context) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 20.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey,
|
||||
borderRadius: BorderRadius.circular(360.0)),
|
||||
height: 7.0,
|
||||
width: 50.0,
|
||||
),
|
||||
SizedBox(height: _size.height * 0.025),
|
||||
const Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
' Profile photo',
|
||||
style: kHeadingStyle,
|
||||
),
|
||||
),
|
||||
SizedBox(height: _size.height * 0.015),
|
||||
Row(
|
||||
children: List.generate(
|
||||
3,
|
||||
(index) => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
MaterialButton(
|
||||
color: _dpBtnColors.map((e) => e).elementAt(index),
|
||||
shape: const CircleBorder(),
|
||||
onPressed: index == 0
|
||||
? () => _removePic()
|
||||
: index == 1
|
||||
? () => _galleryPic()
|
||||
: () => _cameraPic(),
|
||||
child: Icon(
|
||||
_dpBtnIcons.map((e) => e).elementAt(index),
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
_dpBtnText.map((e) => e).elementAt(index),
|
||||
textAlign: TextAlign.center,
|
||||
)
|
||||
],
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _removePic() {
|
||||
setState(() {
|
||||
image = null;
|
||||
_photo = '';
|
||||
});
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
void _cameraPic() async {
|
||||
try {
|
||||
setState(() {
|
||||
_uploading = true;
|
||||
});
|
||||
|
||||
// picking Image from Camera
|
||||
final file = await imgPicker.getImage(
|
||||
source: ImageSource.camera,
|
||||
);
|
||||
|
||||
if (file != null) {
|
||||
image = File(file.path);
|
||||
setState(() {
|
||||
_uploading = false;
|
||||
_photo = file.path;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_uploading = false;
|
||||
});
|
||||
}
|
||||
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
void _galleryPic() async {
|
||||
try {
|
||||
debugPrint('gallery pic');
|
||||
setState(() {
|
||||
_uploading = true;
|
||||
});
|
||||
|
||||
// picking Image from local storage
|
||||
final file = await imgPicker.getImage(
|
||||
source: ImageSource.gallery,
|
||||
);
|
||||
|
||||
if (file != null) {
|
||||
image = File(file.path);
|
||||
setState(() {
|
||||
_uploading = false;
|
||||
_photo = file.path;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_uploading = false;
|
||||
});
|
||||
}
|
||||
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||