diff --git a/SPEC.md b/SPEC.md index 50f07cb..2bd747c 100644 --- a/SPEC.md +++ b/SPEC.md @@ -47,7 +47,7 @@ required - any new Cwtch work is beyond the scope of this initial spec. - [X] Save/Load - [X] Switch Dark / Light Theme - [X] Switch Language -- [ ] Enable/Disable Experiments +- [X] Enable/Disable Experiments - [ ] Accessibility Settings (Zoom etc. - needs a deep dive into flutter) - [X] Display Build & Version Info - [X] Acknowledgements & Credits diff --git a/android/app/build.gradle b/android/app/build.gradle index f5b0d04..e6ebbc7 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -64,4 +64,6 @@ dependencies { implementation project(':cwtch') implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2" + implementation "com.airbnb.android:lottie:3.5.0" + implementation "com.android.support.constraint:constraint-layout:2.0.4" } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a488615..ce5d411 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ @@ -24,15 +24,7 @@ android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> - - + diff --git a/android/app/src/main/kotlin/com/example/flutter_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/flutter_app/MainActivity.kt index bf69dd5..3c1cdca 100644 --- a/android/app/src/main/kotlin/com/example/flutter_app/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/flutter_app/MainActivity.kt @@ -1,5 +1,6 @@ package com.example.flutter_app +import SplashView import androidx.annotation.NonNull import android.content.pm.PackageManager import android.os.Bundle @@ -10,6 +11,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import io.flutter.embedding.android.SplashScreen import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel @@ -25,6 +27,8 @@ import org.json.JSONObject class MainActivity: FlutterActivity() { + override fun provideSplashScreen(): SplashScreen? = SplashView() + // Channel to get app info private val CHANNEL_APP_INFO = "test.flutter.dev/applicationInfo" private val CALL_APP_INFO = "getNativeLibDir" diff --git a/android/app/src/main/kotlin/com/example/flutter_app/SplashView.kt b/android/app/src/main/kotlin/com/example/flutter_app/SplashView.kt new file mode 100644 index 0000000..288957a --- /dev/null +++ b/android/app/src/main/kotlin/com/example/flutter_app/SplashView.kt @@ -0,0 +1,15 @@ +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import com.example.flutter_app.R +import io.flutter.embedding.android.SplashScreen + +class SplashView : SplashScreen { + override fun createSplashView(context: Context, savedInstanceState: Bundle?): View? = + LayoutInflater.from(context).inflate(R.layout.splash_view, null, false) + + override fun transitionToFlutter(onTransitionComplete: Runnable) { + onTransitionComplete.run() + } +} \ No newline at end of file diff --git a/android/app/src/main/res/layout/splash_view.xml b/android/app/src/main/res/layout/splash_view.xml new file mode 100644 index 0000000..85c2362 --- /dev/null +++ b/android/app/src/main/res/layout/splash_view.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/raw/cwtch_animated_logo.json b/android/app/src/main/res/raw/cwtch_animated_logo.json new file mode 100644 index 0000000..b556344 --- /dev/null +++ b/android/app/src/main/res/raw/cwtch_animated_logo.json @@ -0,0 +1 @@ +{"v":"5.7.4","fr":29.9700012207031,"ip":0,"op":168.00000684278,"w":510,"h":510,"nm":"Comp 1","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-45,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":13,"s":[130.813,36.688,0],"to":[15.854,16.521,0],"ti":[-15.854,-16.521,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":17,"s":[225.938,135.813,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":187,"s":[225.938,135.813,0],"to":[-15.854,-16.521,0],"ti":[15.854,16.521,0]},{"t":191.000007779589,"s":[130.813,36.688,0]}],"ix":2,"l":2},"a":{"a":0,"k":[43.563,-24.563,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[44.125,137.125],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.485674749636,0.949019607843,0.850899430817,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[43.563,-24.563],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":13.0000005295009,"op":216.00000879786,"st":13.0000005295009,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Gradient Fill_1","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[163.5,145,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[25.75,-64.625],[6.5,-47.625],[99.25,45.75],[121.125,29.375]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0.411,0.392,0.192,0.486,0.706,0.229,0.127,0.273,1,0.067,0.063,0.059],"ix":9}},"s":{"a":0,"k":[0,0],"ix":5},"e":{"a":0,"k":[100,0],"ix":6},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":13.0000005295009,"op":223.000009082976,"st":13.0000005295009,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 3","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[163.5,145,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":5,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[84.25,32.25],[84.625,30.75],[84.5,31.625],[84.75,29.75],[84.75,30.625],[83.625,29.25],[84.625,31.25],[85,30.375],[98.25,17],[71,-3.25],[61.25,8.125],[61.875,9],[60.875,7.5],[61,8.625],[60.375,9.375],[61.125,9.25],[84.5,30.25],[85.375,30.875]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":5.889,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[57.25,59.5],[57.625,58],[57.5,58.875],[57.75,57],[57.75,57.875],[56.625,56.5],[57.625,58.5],[58,57.625],[98.25,17],[71,-3.25],[36.125,32.25],[36.75,33.125],[35.75,31.625],[35.875,32.75],[35.25,33.5],[36,33.375],[57.5,57.5],[58.375,58.125]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":6.778,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[20.125,98.125],[20.5,96.625],[20.375,97.5],[20.625,95.625],[20.625,96.5],[19.5,95.125],[20.5,97.125],[36.5,82.75],[98.25,17],[71,-3.25],[-0.375,68.5],[0.25,69.375],[-0.75,67.875],[-0.625,69],[-1.25,69.75],[-0.5,69.625],[20.375,96.125],[21.25,96.75]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":7.668,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-21,97.25],[-20.625,95.75],[-20.75,96.625],[-20.5,94.75],[-20.5,95.625],[-21.625,94.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-0.375,68.5],[0.25,69.375],[-0.75,67.875],[-0.625,69],[-1.25,69.75],[-0.5,69.625],[-20.75,95.25],[-19.875,95.875]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":8.556,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-61.375,66.25],[-61,64.75],[-61.125,65.625],[-60.875,63.75],[-60.875,64.625],[-62,63.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-3.75,65.75],[-33.75,37],[-34.75,35.5],[-34.625,36.625],[-35.25,37.375],[-34.5,37.25],[-61.125,64.25],[-60.25,64.875]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":9.444,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-92.875,31.25],[-92.5,29.75],[-92.625,30.625],[-92.375,28.75],[-92.375,29.625],[-62,63.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-3.75,65.75],[-61.75,6],[-62.75,4.5],[-62.625,5.625],[-63.25,6.375],[-62.5,6.25],[-92.625,29.25],[-91.75,29.875]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10.333,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-118.75,-72.875],[-118.375,-74.375],[-118.5,-73.5],[-118,-16.5],[-99,19.75],[-62,63.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-3.75,65.75],[-61.75,6],[-79.5,-25.5],[-82.25,-57.75],[-82.875,-57],[-82.125,-57.125],[-118.5,-74.875],[-117.625,-74.25]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":11.223,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-19,17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[19,-17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-72,-116.5],[-98.5,-99.25],[-118.5,-73.5],[-118,-16.5],[-99,19.75],[-62,63.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-3.75,65.75],[-61.75,6],[-79.5,-25.5],[-82.25,-57.75],[-69.25,-71.375],[-63.75,-71.25],[-62.875,-116.875],[-67.375,-116.875]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":12.111,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-19,17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[19,-17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-72,-116.5],[-98.5,-99.25],[-118.5,-73.5],[-118,-16.5],[-99,19.75],[-62,63.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-3.75,65.75],[-61.75,6],[-79.5,-25.5],[-82.25,-57.75],[-69.25,-71.375],[-63.75,-71.25],[-62.875,-116.875],[-67.375,-116.875]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0},"t":13,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-19,17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[19,-17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-72,-116.5],[-98.5,-99.25],[-118.5,-73.5],[-118,-16.5],[-99,19.75],[-62,63.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-3.75,65.75],[-61.75,6],[-79.5,-25.5],[-82.25,-57.75],[-62.75,-75.5],[-32.75,-65.75],[0.25,-99.25],[-36.75,-115.25]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":191.223,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-19,17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[19,-17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-72,-116.5],[-98.5,-99.25],[-118.5,-73.5],[-118,-16.5],[-99,19.75],[-62,63.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-3.75,65.75],[-61.75,6],[-79.5,-25.5],[-82.25,-57.75],[-62.75,-75.5],[-32.75,-65.75],[0.25,-99.25],[-36.75,-115.25]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":192.111,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-19,17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[19,-17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-72,-116.5],[-98.5,-99.25],[-118.5,-73.5],[-118,-16.5],[-99,19.75],[-62,63.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-3.75,65.75],[-61.75,6],[-79.5,-25.5],[-82.25,-57.75],[-69.25,-71.375],[-63.75,-71.25],[-62.875,-116.875],[-67.375,-116.875]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":193,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-19,17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[19,-17],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-72,-116.5],[-98.5,-99.25],[-118.5,-73.5],[-118,-16.5],[-99,19.75],[-62,63.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-3.75,65.75],[-61.75,6],[-79.5,-25.5],[-82.25,-57.75],[-69.25,-71.375],[-63.75,-71.25],[-62.875,-116.875],[-67.375,-116.875]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":193.89,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-118.75,-72.875],[-118.375,-74.375],[-118.5,-73.5],[-118,-16.5],[-99,19.75],[-62,63.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-3.75,65.75],[-61.75,6],[-79.5,-25.5],[-82.25,-57.75],[-82.875,-57],[-82.125,-57.125],[-118.5,-74.875],[-117.625,-74.25]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":194.779,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-92.875,31.25],[-92.5,29.75],[-92.625,30.625],[-92.375,28.75],[-92.375,29.625],[-62,63.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-3.75,65.75],[-61.75,6],[-62.75,4.5],[-62.625,5.625],[-63.25,6.375],[-62.5,6.25],[-92.625,29.25],[-91.75,29.875]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":195.666,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-61.375,66.25],[-61,64.75],[-61.125,65.625],[-60.875,63.75],[-60.875,64.625],[-62,63.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-3.75,65.75],[-33.75,37],[-34.75,35.5],[-34.625,36.625],[-35.25,37.375],[-34.5,37.25],[-61.125,64.25],[-60.25,64.875]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":196.555,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-21,97.25],[-20.625,95.75],[-20.75,96.625],[-20.5,94.75],[-20.5,95.625],[-21.625,94.25],[-4,112.25],[36.5,82.75],[98.25,17],[71,-3.25],[-0.375,68.5],[0.25,69.375],[-0.75,67.875],[-0.625,69],[-1.25,69.75],[-0.5,69.625],[-20.75,95.25],[-19.875,95.875]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":197.445,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[20.125,98.125],[20.5,96.625],[20.375,97.5],[20.625,95.625],[20.625,96.5],[19.5,95.125],[20.5,97.125],[36.5,82.75],[98.25,17],[71,-3.25],[-0.375,68.5],[0.25,69.375],[-0.75,67.875],[-0.625,69],[-1.25,69.75],[-0.5,69.625],[20.375,96.125],[21.25,96.75]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":198.334,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[57.25,59.5],[57.625,58],[57.5,58.875],[57.75,57],[57.75,57.875],[56.625,56.5],[57.625,58.5],[58,57.625],[98.25,17],[71,-3.25],[36.125,32.25],[36.75,33.125],[35.75,31.625],[35.875,32.75],[35.25,33.5],[36,33.375],[57.5,57.5],[58.375,58.125]],"c":true}]},{"t":199.222508114499,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[84.25,32.25],[84.625,30.75],[84.5,31.625],[84.75,29.75],[84.75,30.625],[83.625,29.25],[84.625,31.25],[85,30.375],[98.25,17],[71,-3.25],[61.25,8.125],[61.875,9],[60.875,7.5],[61,8.625],[60.375,9.375],[61.125,9.25],[84.5,30.25],[85.375,30.875]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.485674749636,0.949019607843,0.850899430817,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":5.00000020365417,"op":215.00000875713,"st":5.00000020365417,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Gradient Fill_2","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,143.75,0],"ix":2,"l":2},"a":{"a":0,"k":[97,108.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.32,-15.32],[-22.18,-37.58],[-8.27,-9.9],[-34.38,-27.34],[-15.84,15.83],[-5.9,6.87],[0,0],[7.34,-7.34],[13.62,-11.5],[0,0],[0,0],[14.29,17.55],[4.55,9.42],[0.38,6.48],[-2.45,5.95],[-6.41,6.41],[-5.83,2.09],[-8.02,-1.44],[0,0],[-4.58,-2.6],[0,0],[11.46,2.33]],"o":[[-28.01,28.01],[5.34,9.04],[18.86,22.58],[22.52,-17.91],[7.26,-7.26],[0,0],[-5.78,6.83],[-10.39,10.39],[0,0],[0,0],[-24.91,-21.03],[-9.08,-11.14],[-3.92,-8.14],[-0.19,-3.16],[2.4,-5.84],[2.39,-2.39],[6.02,-2.16],[0,0],[3.49,0.72],[0,0],[-5.51,-2.83],[-23.38,-4.74]],"v":[[-73.323,-90.495],[-81.753,4.345],[-61.243,32.885],[18.987,108.105],[76.777,57.275],[96.587,36.005],[77.827,17.245],[58.077,38.565],[21.887,71.555],[18.987,73.995],[16.097,71.555],[-42.993,13.415],[-63.523,-17.565],[-70.013,-39.595],[-67.713,-53.595],[-54.623,-71.795],[-42.543,-79.705],[-21.673,-80.775],[-21.563,-80.755],[-9.533,-75.805],[11.627,-96.965],[-14.993,-106.435]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.39199999641,0.19199999641,0.486000001197,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[96.587,108.105],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":5.00000020365417,"op":215.00000875713,"st":5.00000020365417,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"new curve 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[163.5,145,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.5,4],[0,0],[-31,-24.75],[1.25,-1.5]],"o":[[5.5,-4],[0,0],[44.579,35.591],[-1.25,1.5]],"v":[[-65.5,-9.5],[10.75,-84],[79.5,-86.25],[93.5,-13.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":26,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,0,0,0,0.092,0.196,0.096,0.243,0.64,0.392,0.192,0.486],"ix":8}},"s":{"a":0,"k":[0,0],"ix":4},"e":{"a":0,"k":[100,0],"ix":5},"t":1,"lc":1,"lj":1,"ml":4,"ml2":{"a":0,"k":4,"ix":13},"bm":0,"nm":"Gradient Stroke 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":5,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":199,"s":[0]},{"t":206.000008390552,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":5,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":199,"s":[100]},{"t":206.000008390552,"s":[0]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":210.000008553475,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"new curve","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[163.5,145,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.5,4],[0,0],[-31,-24.75],[1.25,-1.5]],"o":[[5.5,-4],[0,0],[44.579,35.591],[-1.25,1.5]],"v":[[-65.5,-9.5],[10.75,-84],[79.5,-86.25],[93.5,-13.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.392156892664,0.192156877705,0.486274539723,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":26,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":5,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":199,"s":[0]},{"t":206.000008390552,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":5,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":199,"s":[100]},{"t":206.000008390552,"s":[0]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":210.000008553475,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"heart1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":0,"k":[119.75,254.25,0],"ix":2,"l":2},"a":{"a":0,"k":[163.5,145,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":327,"h":290,"ip":81.0000032991976,"op":107.000004358199,"st":-103.000004195276,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"heart1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":0,"k":[119.75,254.25,0],"ix":2,"l":2},"a":{"a":0,"k":[163.5,145,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":327,"h":290,"ip":54.0000021994651,"op":81.0000032991976,"st":54.0000021994651,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"heart1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":0,"k":[252.75,388.75,0],"ix":2,"l":2},"a":{"a":0,"k":[163.5,145,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":327,"h":290,"ip":103.000004195276,"op":127.000005172816,"st":-83.0000033806593,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"heart1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":0,"k":[252.75,388.75,0],"ix":2,"l":2},"a":{"a":0,"k":[163.5,145,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":327,"h":290,"ip":35.0000014255792,"op":103.000004195276,"st":35.0000014255792,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"heart1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[389.25,255.25,0],"ix":2,"l":2},"a":{"a":0,"k":[163.5,145,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":327,"h":290,"ip":124.000005050624,"op":147.000005987433,"st":-63.0000025660426,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"heart1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[389.25,255.25,0],"ix":2,"l":2},"a":{"a":0,"k":[163.5,145,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":327,"h":290,"ip":18.000000733155,"op":124.000005050624,"st":18.000000733155,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"heart1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[255,122.25,0],"ix":2,"l":2},"a":{"a":0,"k":[163.5,145,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":327,"h":290,"ip":144.00000586524,"op":168.00000684278,"st":-42.0000017106951,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"heart1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[255,122.25,0],"ix":2,"l":2},"a":{"a":0,"k":[163.5,145,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":327,"h":290,"ip":0,"op":144.00000586524,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 1f83a33..0000000 --- a/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/android/build.gradle b/android/build.gradle index 3100ad2..361fb7a 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,6 +8,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.5.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } } diff --git a/android/cwtch/cwtch.aar b/android/cwtch/cwtch.aar index 2f7f548..10e699d 100644 Binary files a/android/cwtch/cwtch.aar and b/android/cwtch/cwtch.aar differ diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index 0f59776..340e162 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -47,6 +47,8 @@ "dontSavePeerHistory": "Peer-Verlauf löschen", "editProfile": "Profil bearbeiten", "editProfileTitle": "Profil bearbeiten", + "enableGroups": "", + "enterCurrentPasswordForDelete": "", "enterProfilePassword": "Geben Sie ein Passwort ein, um Ihre Profile anzuzeigen", "error0ProfilesLoadedForPassword": "0 Profile mit diesem Passwort geladen", "experimentsEnabled": "Experimente aktiviert", diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 8704392..15e3f20 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -47,9 +47,11 @@ "dontSavePeerHistory": "Delete Peer History", "editProfile": "Edit Profille", "editProfileTitle": "Edit Profile", + "enableGroups": "Enable Group Chat", + "enterCurrentPasswordForDelete": "Please enter current password to delete this profile.", "enterProfilePassword": "Enter a password to view your profiles", "error0ProfilesLoadedForPassword": "0 profiles loaded with that password", - "experimentsEnabled": "Experiments enabled", + "experimentsEnabled": "Enable Experiments", "groupAddr": "Address", "groupName": "Group name", "groupNameLabel": "Group Name", diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index 023d7eb..661e351 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -47,6 +47,8 @@ "dontSavePeerHistory": "Eliminar historial de contacto", "editProfile": "Editar perfil", "editProfileTitle": "Editar perfil", + "enableGroups": "", + "enterCurrentPasswordForDelete": "", "enterProfilePassword": "Ingresa tu contraseña para ver tus perfiles", "error0ProfilesLoadedForPassword": "0 perfiles cargados con esa contraseña", "experimentsEnabled": "Experimentos habilitados", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index ea7b94f..56bf040 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -47,6 +47,8 @@ "dontSavePeerHistory": "", "editProfile": "", "editProfileTitle": "", + "enableGroups": "", + "enterCurrentPasswordForDelete": "", "enterProfilePassword": "", "error0ProfilesLoadedForPassword": "", "experimentsEnabled": "", diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index 5526c92..6fd0a19 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -47,6 +47,8 @@ "dontSavePeerHistory": "Elimina cronologia dei peer", "editProfile": "Modifica profilo", "editProfileTitle": "Modifica profilo", + "enableGroups": "", + "enterCurrentPasswordForDelete": "", "enterProfilePassword": "Inserisci una password per visualizzare i tuoi profili", "error0ProfilesLoadedForPassword": "0 profili caricati con quella password", "experimentsEnabled": "Esperimenti abilitati", diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index 4812797..f1ccc09 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -47,6 +47,8 @@ "dontSavePeerHistory": "", "editProfile": "", "editProfileTitle": "", + "enableGroups": "", + "enterCurrentPasswordForDelete": "", "enterProfilePassword": "", "error0ProfilesLoadedForPassword": "", "experimentsEnabled": "", diff --git a/lib/licenses.dart b/lib/licenses.dart new file mode 100644 index 0000000..85d07da --- /dev/null +++ b/lib/licenses.dart @@ -0,0 +1,118 @@ +import 'package:flutter/foundation.dart'; + +Stream licenses() async* { + /// Open Privacy Code + yield LicenseEntryWithLineBreaks(["cwtch", "tapir", "connectivity", "log"], '''MIT License + + Copyright (c) 2018 Open Privacy Research Society + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files ("the Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.'''); + + /// Ristretto Code + yield LicenseEntryWithLineBreaks(["ristretto255"], '''Copyright (c) 2009 The Go Authors. All rights reserved. +Copyright (c) 2017 George Tankersley. All rights reserved. +Copyright (c) 2019 Henry de Valence. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.'''); + + /// Package pretty provides pretty-printing for Go values. (via Cwtch) + yield LicenseEntryWithLineBreaks(["pretty"], '''Copyright 2012 Keith Rarick + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.'''); + + yield LicenseEntryWithLineBreaks(["pidusage"], '''MIT License + +Copyright (c) 2017 David 大伟 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.'''); + + + /// Go Standard Lib + yield LicenseEntryWithLineBreaks(["crypto, net"], '''Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.'''); +} diff --git a/lib/main.dart b/lib/main.dart index b5c3fb4..742a4db 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter_app/cwtch/ffi.dart'; import 'package:flutter_app/cwtch/gomobile.dart'; import 'package:flutter/material.dart'; @@ -6,6 +7,7 @@ import 'package:flutter_app/views/triplecolview.dart'; import 'package:provider/provider.dart'; import 'cwtch/cwtch.dart'; import 'cwtch/cwtchNotifier.dart'; +import 'licenses.dart'; import 'model.dart'; import 'views/profilemgrview.dart'; import 'views/splashView.dart'; @@ -13,9 +15,13 @@ import 'dart:io' show Platform; import 'opaque.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -var GlobalSettings = Settings(Locale("en", ''), Opaque.dark); +var globalSettings = Settings(Locale("en", ''), Opaque.dark); -void main() => runApp(Flwtch()); + +void main() { + LicenseRegistry.addLicense(() => licenses()); + runApp(Flwtch()); +} class Flwtch extends StatefulWidget { final Key flwtch = GlobalKey(); @@ -41,7 +47,7 @@ class FlwtchState extends State { cwtchInit = false; profs = ProfileListState(); - var cwtchNotifier = new CwtchNotifier(profs, GlobalSettings); + var cwtchNotifier = new CwtchNotifier(profs, globalSettings); if (Platform.isAndroid) { cwtch = CwtchGomobile(cwtchNotifier); @@ -59,7 +65,7 @@ class FlwtchState extends State { } ChangeNotifierProvider getSettingsProvider() => - ChangeNotifierProvider(create: (context) => GlobalSettings); + ChangeNotifierProvider(create: (context) => globalSettings); Provider getFlwtchStateProvider() => Provider(create: (_) => this); ChangeNotifierProvider getProfileListProvider() => diff --git a/lib/settings.dart b/lib/settings.dart index 62e789a..f9d047b 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -1,3 +1,4 @@ +import 'dart:collection'; import 'dart:ui'; import 'dart:core'; @@ -6,38 +7,57 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'opaque.dart'; +/// Settings govern the *Globally* relevant settings like Locale, Theme and Experiments. +/// We also provide access to the version information here as it is also accessed from the +/// Settings Pane. class Settings extends ChangeNotifier { Locale locale; - PackageInfo packageInfo; - OpaqueThemeType theme; + bool experimentsEnabled; + HashMap experiments = HashMap.identity(); + /// Set the dark theme. void setDark() { theme = Opaque.dark; notifyListeners(); } + /// Set the Light theme. void setLight() { theme = Opaque.light; notifyListeners(); } + /// Get access to the current theme. OpaqueThemeType current() { return theme; } + /// Called by the event bus. When new settings are loaded from a file the JSON will + /// be sent to the function and new settings will be instantiated based on the contents. handleUpdate(dynamic settings) { - print("Settings ${settings}"); - switchLocale(Locale(settings["Locale"])); + // Set Theme and notify listeners if (settings["Theme"] == "light") { this.setLight(); } else { this.setDark(); } + + // Set Locale and notify listeners + switchLocale(Locale(settings["Locale"])); + + // Decide whether to enable Experiments + experimentsEnabled = settings["ExperimentsEnabled"]; + + // Set the internal experiments map. Casting from the Map that we get from JSON + experiments = new HashMap.from(settings["Experiments"]); + + // Push the experimental settings to Consumers of Settings notifyListeners(); } + /// Initialize the Package Version information initPackageInfo() { PackageInfo.fromPlatform().then((PackageInfo newPackageInfo) { packageInfo = newPackageInfo; @@ -45,13 +65,42 @@ class Settings extends ChangeNotifier { }); } + // Switch the Locale of the App switchLocale(Locale newLocale) { locale = newLocale; notifyListeners(); } + /// Turn Experiments On, this will also have the side effect of enabling any + /// Experiments that have been previously activated. + enableExperiments() { + experimentsEnabled = true; + notifyListeners(); + } + + /// Turn Experiments Off. This will disable **all** active experiments. + /// Note: This will not set the preference for individual experiments, if experiments are enabled + /// any experiments that were active previously will become active again unless they are explicitly disabled. + disableExperiments() { + experimentsEnabled = false; + notifyListeners(); + } + + /// Turn on a specific experiment. + enableExperiment(String key) { + experiments.update(key, (value) => true, ifAbsent: () => true); + } + + /// Turn off a specific experiment + disableExperiment(String key) { + experiments.update(key, (value) => false, ifAbsent: () => false); + } + + /// Construct a default settings object. Settings(this.locale, this.theme); + /// Convert this Settings object to a JSON representation for serialization on the + /// event bus. dynamic asJson() { var themeString = "light"; if (theme == Opaque.dark) { @@ -62,8 +111,8 @@ class Settings extends ChangeNotifier { "Locale": this.locale.languageCode, "Theme": themeString, "PreviousPid": -1, - "ExperimentsEnabled": false, - "Experiments": {}, + "ExperimentsEnabled": this.experimentsEnabled, + "Experiments": experiments, "StateRootPane": 0, "FirstTime": false }; diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index eb3af99..2c276db 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -359,8 +359,9 @@ class _AddEditProfileViewState extends State { SizedBox( height: 20, ), + Tooltip(message: AppLocalizations.of(context).enterCurrentPasswordForDelete, child: ElevatedButton.icon( - onPressed: () { + onPressed: checkCurrentPassword() ? null : () { showAlertDialog(context); }, style: ElevatedButton.styleFrom( @@ -368,10 +369,11 @@ class _AddEditProfileViewState extends State { .current() .defaultButtonColor()), icon: Icon(Icons.delete_forever), + label: Text( AppLocalizations.of(context) .deleteBtn), - ) + )) ])) ])))))); }); @@ -452,6 +454,12 @@ class _AddEditProfileViewState extends State { } } } + + // TODO Stub - wire this into a libCwtch call. + bool checkCurrentPassword() { + return ctrlrOldPass.value.text.isEmpty; + } + } showAlertDialog(BuildContext context) { @@ -503,3 +511,4 @@ showAlertDialog(BuildContext context) { }, ); } + diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 178bbd7..21944b5 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -9,6 +9,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import '../main.dart'; +/// Global Settings View provides access to modify all the Globally Relevant Settings including Locale, Theme and Experiments. class GlobalSettingsView extends StatefulWidget { @override _GlobalSettingsViewState createState() => _GlobalSettingsViewState(); @@ -24,76 +25,137 @@ class _GlobalSettingsViewState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(AppLocalizations.of(context).cwtchSettingsTitle), + title: Text(AppLocalizations + .of(context) + .cwtchSettingsTitle), ), body: _buildSettingsList(), ); } Widget _buildSettingsList() { - return Consumer(builder: (context, theme, child) { - return Center( - child: Column(children: [ - ListTile( - title: Text(AppLocalizations.of(context).settingLanguage, - style: TextStyle(color: theme.current().mainTextColor())), - leading: - Icon(Icons.language, color: theme.current().mainTextColor()), - trailing: DropdownButton( - value: Provider.of(context).locale.languageCode, - onChanged: (String newValue) { - setState(() { - var settings = - Provider.of(context, listen: false); - settings.switchLocale(Locale(newValue, '')); - saveSettings(context); - }); - }, - items: AppLocalizations.supportedLocales - .map>((Locale value) { - return DropdownMenuItem( - value: value.languageCode, - child: Text(getLanguageFull(context, value.languageCode)), - ); - }).toList())), - SwitchListTile( - title: Text(AppLocalizations.of(context).settingTheme, - style: TextStyle(color: theme.current().mainTextColor())), - value: theme.current() == Opaque.light, - onChanged: (bool value) { - if (value) { - theme.setLight(); - } else { - theme.setDark(); - } + return Consumer(builder: (context, settings, child) { + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints viewportConstraints) { + return Scrollbar( + isAlwaysShown: true, + child: SingleChildScrollView( + clipBehavior: Clip.antiAlias, + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Column(children: [ + ListTile( + title: Text(AppLocalizations + .of(context) + .settingLanguage, + style: TextStyle(color: settings.current().mainTextColor())), + leading: + Icon(Icons.language, color: settings.current().mainTextColor()), + trailing: DropdownButton( + value: Provider + .of(context) + .locale + .languageCode, + onChanged: (String newValue) { + setState(() { + settings.switchLocale(Locale(newValue, '')); + saveSettings(context); + }); + }, + items: AppLocalizations.supportedLocales + .map>((Locale value) { + return DropdownMenuItem( + value: value.languageCode, + child: Text(getLanguageFull(context, value.languageCode)), + ); + }).toList())), + SwitchListTile( + title: Text(AppLocalizations + .of(context) + .settingTheme, + style: TextStyle(color: settings.current().mainTextColor())), + value: settings.current() == Opaque.light, + onChanged: (bool value) { + if (value) { + settings.setLight(); + } else { + settings.setDark(); + } - // Save Settings... - saveSettings(context); - }, - secondary: Icon(Icons.lightbulb_outline, - color: theme.current().mainTextColor()), - ), - AboutListTile( - icon: Icon(Icons.info, color: theme.current().mainTextColor()), - applicationIcon: Padding( - padding: EdgeInsets.all(20), - child: Image( - image: AssetImage("assets/knott.png"), - width: 128, - height: 128, - )), - applicationName: "Cwtch (Flutter UI)", - applicationVersion: AppLocalizations.of(context).version.replaceAll( - "%1", - constructVersionString( - Provider.of(context).packageInfo)), - applicationLegalese: '\u{a9} 2021 Open Privacy Research Society', - ), - ])); + // Save Settings... + saveSettings(context); + }, + secondary: Icon(Icons.lightbulb_outline, + color: settings.current().mainTextColor()), + ), + SwitchListTile( + title: Text(AppLocalizations + .of(context) + .experimentsEnabled, + style: TextStyle(color: settings.current().mainTextColor())), + value: settings.experimentsEnabled, + onChanged: (bool value) { + if (value) { + settings.enableExperiments(); + } else { + settings.disableExperiments(); + } + // Save Settings... + saveSettings(context); + }, + secondary: Icon(Icons.science, + color: settings.current().mainTextColor()), + ), + Visibility(visible: settings.experimentsEnabled, child: Column(children: [ + SwitchListTile( + title: Text(AppLocalizations + .of(context) + .enableGroups, + style: TextStyle(color: settings.current().mainTextColor())), + value: settings.experiments.containsKey("tapir-groups-experiment") && settings.experiments["tapir-groups-experiment"], + onChanged: (bool value) { + if (value) { + settings.enableExperiment("tapir-groups-experiment"); + } else { + settings.disableExperiment("tapir-groups-experiment"); + } + // Save Settings... + saveSettings(context); + }, + secondary: Icon(Icons.group_sharp, + color: settings.current().mainTextColor()), + ), + ],)), + AboutListTile( + icon: Icon(Icons.info, color: settings.current().mainTextColor()), + applicationIcon: Padding( + padding: EdgeInsets.all(20), + child: Image( + image: AssetImage("assets/knott.png"), + width: 128, + height: 128, + )), + applicationName: "Cwtch (Flutter UI)", + applicationVersion: AppLocalizations + .of(context) + .version + .replaceAll( + "%1", + constructVersionString( + Provider + .of(context) + .packageInfo)), + applicationLegalese: '\u{a9} 2021 Open Privacy Research Society', + ), + ])))); + }); }); } } +/// Construct a version string from Package Info String constructVersionString(PackageInfo pinfo) { if (pinfo == null) { return ""; @@ -101,6 +163,8 @@ String constructVersionString(PackageInfo pinfo) { return pinfo.version + "." + pinfo.buildNumber; } +/// A slightly verbose way to extract the full language name from +/// an individual language code. There might be a more efficient way of doing this. String getLanguageFull(context, String languageCode) { if (languageCode == "en") { return AppLocalizations.of(context).localeEn; @@ -123,6 +187,7 @@ String getLanguageFull(context, String languageCode) { return languageCode; } +/// Send an UpdateGlobalSettings to the Event Bus saveSettings(context) { var settings = Provider.of(context, listen: false); final updateSettingsEvent = { diff --git a/lib/widgets/buttontextfield.dart b/lib/widgets/buttontextfield.dart index e50fa16..cc03b73 100644 --- a/lib/widgets/buttontextfield.dart +++ b/lib/widgets/buttontextfield.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_app/settings.dart'; import 'package:provider/provider.dart'; -import '../opaque.dart'; + // Provides a styled Text Field for use in Form Widgets. // Callers must provide a text controller, label helper text and a validator. diff --git a/lib/widgets/cwtchlabel.dart b/lib/widgets/cwtchlabel.dart index 6780198..a2e062d 100644 --- a/lib/widgets/cwtchlabel.dart +++ b/lib/widgets/cwtchlabel.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import '../opaque.dart'; import '../settings.dart'; // Provides a styled Label diff --git a/lib/widgets/passwordfield.dart b/lib/widgets/passwordfield.dart index 5853d1f..c7c6850 100644 --- a/lib/widgets/passwordfield.dart +++ b/lib/widgets/passwordfield.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import '../opaque.dart'; import '../settings.dart'; // Provides a styled Password Input Field for use in Form Widgets. diff --git a/lib/widgets/profilerow.dart b/lib/widgets/profilerow.dart index b044e10..6130399 100644 --- a/lib/widgets/profilerow.dart +++ b/lib/widgets/profilerow.dart @@ -6,7 +6,6 @@ import 'package:provider/provider.dart'; import '../main.dart'; import '../model.dart'; -import '../opaque.dart'; import '../settings.dart'; class ProfileRow extends StatefulWidget { diff --git a/lib/widgets/textfield.dart b/lib/widgets/textfield.dart index f2a31b3..33a1a24 100644 --- a/lib/widgets/textfield.dart +++ b/lib/widgets/textfield.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import '../opaque.dart'; import '../settings.dart'; // Provides a styled Text Field for use in Form Widgets. diff --git a/pubspec.yaml b/pubspec.yaml index ec288c7..0319339 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,7 +35,6 @@ dependencies: ffi: ^1.0.0 path_provider: ^2.0.0 - dev_dependencies: flutter_test: sdk: flutter