diff --git a/.gitmodules b/.gitmodules index eb71f2df5..95b02e580 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,7 +6,4 @@ url = https://github.com/cypherstack/flutter_libmonero.git [submodule "crypto_plugins/flutter_liblelantus"] path = crypto_plugins/flutter_liblelantus - url = https://github.com/cypherstack/flutter_liblelantus.git -[submodule "crypto_plugins/tor"] - path = crypto_plugins/tor - url = https://github.com/cypherstack/tor.git \ No newline at end of file + url = https://github.com/cypherstack/flutter_liblelantus.git \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index dda3aabee..ec8747bff 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -34,7 +34,9 @@ if (keystorePropertiesFile.exists()) { android { compileSdkVersion 33 - ndkVersion = "21.1.6352462" +// ndkVersion = "21.1.6352462" +// ndkVersion = "25.2.9519653" + ndkVersion = "23.1.7779620" sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -49,7 +51,9 @@ android { applicationId "com.cypherstack.stackwallet" minSdkVersion 23 targetSdkVersion 33 - ndkVersion = "21.1.6352462" +// ndkVersion = "21.1.6352462" +// ndkVersion = "25.2.9519653" + ndkVersion = "23.1.7779620" versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/android/build.gradle b/android/build.gradle index f7eb7f63c..baa7dd294 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.7.10' + ext.kotlin_version = '1.8.0' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:7.3.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/assets/lottie/onion_animation.json b/assets/lottie/onion_animation.json new file mode 100644 index 000000000..9988b5a7c --- /dev/null +++ b/assets/lottie/onion_animation.json @@ -0,0 +1 @@ +{"v":"5.10.2","fr":25,"ip":0,"op":436,"w":180,"h":180,"nm":"onion-character-animation","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"failed","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150.3,44.3,0],"ix":2,"l":2},"a":{"a":0,"k":[17.188,17.188,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":393,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":408,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":414,"s":[108,108,100]},{"t":429,"s":[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]],"o":[[0,0],[0,0]],"v":[[-6.919,6.919],[6.919,-6.919]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.878431432387,0.415686304429,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":[17.188,17.187],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.919,-6.919],[6.919,6.919]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.878431432387,0.415686304429,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":[17.188,17.188],"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 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.388,0],[0,-8.388],[8.388,0],[0,8.387]],"o":[[8.388,0],[0,8.387],[-8.388,0],[0,-8.388]],"v":[[0,-15.188],[15.188,0.001],[0,15.188],[-15.188,0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.513725490196,0.513725490196,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":[17.188,17.188],"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 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"globe","sr":1,"ks":{"o":{"a":1,"k":[{"t":195,"s":[100],"h":1},{"t":213,"s":[0],"h":1},{"t":378,"s":[100],"h":1},{"t":427,"s":[0],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150.25,44.25,0],"ix":2,"l":2},"a":{"a":0,"k":[17.188,17.188,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":32,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":47,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":53,"s":[108,108,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":68,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":328,"s":[100,100,100]},{"t":341,"s":[0,0,100],"h":1},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":378,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":390,"s":[100,100,100]},{"t":427,"s":[0,0,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]],"o":[[0,0],[0,0]],"v":[[2.001,17.795],[32.376,17.795]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[17.33,2],[17.33,32.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"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":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-4.233,0],[-1.818,-2.345]],"o":[[1.817,-2.345],[4.233,0],[0,0]],"v":[[-9.721,1.975],[-0.001,-1.975],[9.721,1.975]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"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":[17.188,27.059],"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 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-4.589,0],[-1.622,2.672]],"o":[[1.622,2.672],[4.589,0],[0,0]],"v":[[-10.14,-2.278],[0,2.278],[10.14,-2.278]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"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":[17.188,8.227],"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 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.026,0],[0,-8.388],[4.026,0],[0,8.387]],"o":[[4.026,0],[0,8.387],[-4.026,0],[0,-8.388]],"v":[[0,-15.188],[7.29,0.001],[0,15.188],[-7.29,0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"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":[17.188,17.188],"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 5","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.388,0],[0,-8.388],[8.388,0],[0,8.387]],"o":[[8.388,0],[0,8.387],[-8.388,0],[0,-8.388]],"v":[[0,-15.188],[15.188,0.001],[0,15.188],[-15.188,0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.878431432387,0.415686304429,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":[17.188,17.188],"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 6","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"globe 2","sr":1,"ks":{"o":{"a":1,"k":[{"t":195,"s":[0],"h":1},{"t":213,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150.25,44.25,0],"ix":2,"l":2},"a":{"a":0,"k":[17.188,17.188,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":32,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":47,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":53,"s":[108,108,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":68,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":328,"s":[100,100,100]},{"t":341,"s":[0,0,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]],"o":[[0,0],[0,0]],"v":[[2.001,17.795],[32.376,17.795]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"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":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[17.33,2],[17.33,32.375]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"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":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-4.233,0],[-1.818,-2.345]],"o":[[1.817,-2.345],[4.233,0],[0,0]],"v":[[-9.721,1.975],[-0.001,-1.975],[9.721,1.975]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"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":[17.188,27.059],"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 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-4.589,0],[-1.622,2.672]],"o":[[1.622,2.672],[4.589,0],[0,0]],"v":[[-10.14,-2.278],[0,2.278],[10.14,-2.278]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"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":[17.188,8.227],"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 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.026,0],[0,-8.388],[4.026,0],[0,8.387]],"o":[[4.026,0],[0,8.387],[-4.026,0],[0,-8.388]],"v":[[0,-15.188],[7.29,0.001],[0,15.188],[-7.29,0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"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":[17.188,17.188],"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 5","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.388,0],[0,-8.388],[8.388,0],[0,8.387]],"o":[[8.388,0],[0,8.387],[-8.388,0],[0,-8.388]],"v":[[0,-15.188],[15.188,0.001],[0,15.188],[-15.188,0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.901960784314,0.803921568627,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":[17.188,17.188],"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 6","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":3,"nm":"null-indicator","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":38,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":75,"s":[153.988]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":165,"s":[514]},{"t":211,"s":[720],"h":1},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":378,"s":[514]},{"t":424,"s":[720]}],"ix":10},"p":{"a":0,"k":[150.125,44.219,0],"ix":2,"l":2},"a":{"a":0,"k":[60.125,-45.781,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"indicator-left ","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[50.969,-46.99,0],"ix":2,"l":2},"a":{"a":0,"k":[12.968,22.698,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":40,"s":[0,0,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":45,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":51,"s":[108,108,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":66,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":191,"s":[100,100,100]},{"t":218,"s":[0,0,100],"h":1},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":378,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":385,"s":[100,100,100]},{"t":402,"s":[0,0,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.932,0],[0,-0.931],[0.932,0],[0,0.932]],"o":[[0.932,0],[0,0.932],[-0.932,0],[0,-0.931]],"v":[[0,-1.688],[1.687,-0.001],[0,1.688],[-1.687,-0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.878431432387,0.415686304429,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":[22.249,3.688],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-10.616],[-8.447,-2.437]],"o":[[-10.394,0.857],[0,9.232],[0,0]],"v":[[9.281,-19.82],[-9.281,0.361],[5.343,19.82]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[11.281,23.576],"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 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"indicator-right ","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[69.531,-44.51,0],"ix":2,"l":2},"a":{"a":0,"k":[12.968,22.698,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":40,"s":[0,0,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":45,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":51,"s":[108,108,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":66,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":191,"s":[100,100,100]},{"t":218,"s":[0,0,100],"h":1},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":378,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":385,"s":[100,100,100]},{"t":402,"s":[0,0,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.932,0],[0,-0.931],[0.932,0],[0,0.932]],"o":[[0.932,0],[0,0.932],[-0.932,0],[0,-0.931]],"v":[[0,-1.688],[1.687,-0.001],[0,1.688],[-1.687,-0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.878431432387,0.415686304429,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":[3.687,41.708],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-9.232],[10.395,-0.857]],"o":[[8.447,2.438],[0,10.615],[0,0]],"v":[[-5.344,-19.82],[9.281,-0.361],[-9.281,19.82]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[14.655,21.819],"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 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"network-small","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":235,"s":[100]},{"t":243,"s":[0],"h":1},{"t":265,"s":[100],"h":1},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":319,"s":[100]},{"t":327,"s":[0],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[168.65,44.817,0],"ix":2,"l":2},"a":{"a":0,"k":[3.912,13.78,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":211,"s":[0,0,100]},{"t":222,"s":[100,100,100],"h":1},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":265,"s":[0,0,100]},{"t":276,"s":[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,-4.365],[2.407,-3.331]],"o":[[2.348,3.306],[0,4.424],[0,0]],"v":[[-1.816,-11.78],[1.913,-0.067],[-1.913,11.78]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[3.913,13.78],"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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"network-small","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":235,"s":[100]},{"t":243,"s":[0],"h":1},{"t":265,"s":[100],"h":1},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":319,"s":[100]},{"t":327,"s":[0],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[131.975,44.817,0],"ix":2,"l":2},"a":{"a":0,"k":[3.912,13.78,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":211,"s":[0,0,100]},{"t":222,"s":[100,100,100],"h":1},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":265,"s":[0,0,100]},{"t":276,"s":[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,-4.365],[-2.407,-3.331]],"o":[[-2.348,3.306],[0,4.424],[0,0]],"v":[[1.816,-11.78],[-1.913,-0.067],[1.913,11.78]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[3.912,13.78],"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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"network-large","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":246,"s":[100]},{"t":254,"s":[0],"h":1},{"t":276,"s":[100],"h":1},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":308,"s":[100]},{"t":316,"s":[0],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[172.999,44.817,0],"ix":2,"l":2},"a":{"a":0,"k":[4.625,17.738,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":222,"s":[0,0,100]},{"t":233,"s":[100,100,100],"h":1},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":276,"s":[0,0,100]},{"t":287,"s":[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,-5.868],[3.298,-4.406]],"o":[[3.238,4.383],[0,5.927],[0,0]],"v":[[-2.527,-15.738],[2.626,-0.066],[-2.626,15.738]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[4.625,17.737],"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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"network-large","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":246,"s":[100]},{"t":254,"s":[0],"h":1},{"t":276,"s":[100],"h":1},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":308,"s":[100]},{"t":316,"s":[0],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[127.626,44.817,0],"ix":2,"l":2},"a":{"a":0,"k":[4.625,17.738,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":222,"s":[0,0,100]},{"t":233,"s":[100,100,100],"h":1},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":276,"s":[0,0,100]},{"t":287,"s":[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,-5.868],[-3.298,-4.406]],"o":[[-3.238,4.383],[0,5.927],[0,0]],"v":[[2.527,-15.738],[-2.626,-0.066],[2.626,15.738]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[4.625,17.737],"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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":3,"nm":"null-body ","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":225,"s":[-10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":243,"s":[10]},{"t":252,"s":[0]}],"ix":10},"p":{"a":0,"k":[90,101,0],"ix":2,"l":2},"a":{"a":0,"k":[0,11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"hand-right ","parent":11,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":23,"s":[26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":308,"s":[26]},{"t":317,"s":[0],"h":1},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":378,"s":[26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":414,"s":[26]},{"t":423,"s":[0]}],"ix":10},"p":{"a":0,"k":[31.615,10.647,0],"ix":2,"l":2},"a":{"a":0,"k":[7.62,2.379,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.469,-0.257],[14.905,-11.105],[-2.867,9.613],[-4.387,7.038]],"o":[[-0.146,-0.515],[4.244,2.323],[0,0],[0,0],[0,0]],"v":[[-6.294,-13.745],[-5.426,-14.434],[-3.238,7.488],[-8.799,5.079],[-3.74,-4.723]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.572549019608,0.478431402468,0.839215746113,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":[13.667,16.691],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"hand-left ","parent":11,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":23,"s":[-26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":308,"s":[-26]},{"t":317,"s":[0],"h":1},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":378,"s":[-26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":414,"s":[-26]},{"t":423,"s":[0]}],"ix":10},"p":{"a":0,"k":[-31.366,10.897,0],"ix":2,"l":2},"a":{"a":0,"k":[19.478,2.629,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.471,-0.258],[-14.903,-11.103],[2.867,9.613],[4.387,7.037]],"o":[[0.146,-0.516],[-4.246,2.325],[0,0],[0,0],[0,0]],"v":[[6.292,-13.742],[5.421,-14.433],[3.238,7.488],[8.798,5.078],[3.738,-4.722]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.572549019608,0.478431402468,0.839215746113,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":[13.665,16.691],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"eyes ","parent":11,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[0.213,-2.898,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[0.463,3,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[0.463,3,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":58,"s":[0.2,-2.898,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79,"s":[0.2,-2.9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[-6.787,-2.898,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96,"s":[-6.8,-2.899,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100,"s":[0.2,-2.9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":133,"s":[0.2,-2.9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":136,"s":[5,-9.9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":151,"s":[5,-9.9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":155,"s":[0.2,-2.9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":297,"s":[0.213,-2.898,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":303,"s":[0.463,3,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":322,"s":[0.463,3,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":329,"s":[0.2,-2.898,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":408,"s":[0.213,-2.898,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":414,"s":[0.463,3,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":422,"s":[0.463,3,0],"to":[0,0,0],"ti":[0,0,0]},{"t":429,"s":[0.2,-2.898,0]}],"ix":2,"l":2},"a":{"a":0,"k":[17.045,9.606,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":19,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":23,"s":[100,7.967,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":37,"s":[100,8,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":40,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":112,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":114,"s":[100,8,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":118,"s":[100,8,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":120,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":169,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":171,"s":[100,8,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":175,"s":[100,8,100]},{"t":178,"s":[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,-4.201],[1.872,0],[0,4.201],[-1.873,0]],"o":[[0,4.201],[-1.873,0],[0,-4.201],[1.872,0]],"v":[[3.391,0],[-0.001,7.606],[-3.391,0],[-0.001,-7.606]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,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":[28.7,9.606],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-4.201],[1.873,0],[0,4.201],[-1.872,0]],"o":[[0,4.201],[-1.872,0],[0,-4.201],[1.873,0]],"v":[[3.391,0],[-0.001,7.606],[-3.391,0],[-0.001,-7.606]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,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":[5.391,9.606],"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 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"socket ","parent":11,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[31.022,33.297,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":23,"s":[23,33.297,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":308,"s":[23,33.297,0],"to":[0,0,0],"ti":[0,0,0]},{"t":318,"s":[31.022,33.297,0],"h":1},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":378,"s":[23,33.297,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":414,"s":[23,33.297,0],"to":[0,0,0],"ti":[0,0,0]},{"t":424,"s":[31.022,33.297,0]}],"ix":2,"l":2},"a":{"a":0,"k":[24.058,14.693,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],[-1.1,0],[0,0],[0,-1.1],[0,0],[1.1,0],[0,0],[0,1.1]],"o":[[0,-1.1],[0,0],[1.1,0],[0,0],[0,1.1],[0,0],[-1.1,0],[0,0]],"v":[[-2.435,-7.07],[-0.435,-9.07],[0.435,-9.07],[2.435,-7.07],[2.435,7.07],[0.435,9.07],[-0.435,9.07],[-2.435,7.07]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705942191,0.901960844152,0.658823529412,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":[4.435,11.07],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,-3.981],[3.98,0],[0,0]],"o":[[0,0],[3.98,0],[0,3.981],[0,0],[0,0]],"v":[[-6.771,-7.208],[-0.438,-7.208],[6.771,0.001],[-0.438,7.208],[-6.771,7.208]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.878431432387,0.415686304429,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":[10.534,11.07],"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 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.696,0.681],[4.036,0.072],[0,0],[-17.923,-16.81],[0.72,-0.711]],"o":[[-13.443,-13.126],[0,0],[0,0],[0.739,0.693],[-0.693,0.685]],"v":[[12.516,9.362],[-15.743,-4.76],[-15.743,-7.963],[15.001,6.767],[15.023,9.345]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.768627510819,0.768627510819,0.768627510819,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":[30.373,17.343],"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 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"plug ","parent":11,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[-26.789,33.296,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":23,"s":[-18,33.296,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":308,"s":[-18,33.296,0],"to":[0,0,0],"ti":[0,0,0]},{"t":317,"s":[-26.789,33.296,0],"h":1},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":378,"s":[-18,33.296,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":414,"s":[-18,33.296,0],"to":[0,0,0],"ti":[0,0,0]},{"t":423,"s":[-26.789,33.296,0]}],"ix":2,"l":2},"a":{"a":0,"k":[27.268,14.693,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],[1.1,0],[0,0],[0,1.101],[0,0],[-1.1,0],[0,0],[0,-1.099]],"o":[[0,1.101],[0,0],[-1.1,0],[0,0],[0,-1.099],[0,0],[1.1,0],[0,0]],"v":[[2.435,7.07],[0.435,9.07],[-0.435,9.07],[-2.435,7.07],[-2.435,-7.07],[-0.435,-9.07],[0.435,-9.07],[2.435,-7.07]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705942191,0.901960844152,0.658823529412,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.486,11.07],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.82,0],[0,0],[0,0],[0,0],[0,-0.821]],"o":[[0,0],[0,0],[0,0],[0.82,0],[0,0.819]],"v":[[3.933,1.484],[-5.417,1.484],[-5.417,-1.484],[3.933,-1.484],[5.417,0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.768627510819,0.768627510819,0.768627510819,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":[47.119,14.778],"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 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.82,0],[0,0],[0,0],[0,0],[0,-0.82]],"o":[[0,0],[0,0],[0,0],[0.82,0],[0,0.819]],"v":[[3.933,1.484],[-5.417,1.484],[-5.417,-1.484],[3.933,-1.484],[5.417,0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.768627510819,0.768627510819,0.768627510819,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":[47.119,7.363],"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 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,3.981],[-3.981,0],[0,0]],"o":[[0,0],[-3.981,0],[0,-3.981],[0,0],[0,0]],"v":[[6.771,7.208],[0.438,7.208],[-6.771,0.001],[0.438,-7.208],[6.771,-7.208]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.878431432387,0.415686304429,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":[37.387,11.07],"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 4","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.696,0.681],[-4.036,0.072],[0,0],[17.924,-16.81],[-0.72,-0.711]],"o":[[13.443,-13.126],[0,0],[0,0],[-0.738,0.693],[0.693,0.685]],"v":[[-12.515,9.362],[15.742,-4.76],[15.742,-7.963],[-15.001,6.767],[-15.022,9.345]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.768627510819,0.768627510819,0.768627510819,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":[17.742,17.343],"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 5","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"body ","parent":11,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.017,-4.078,0],"ix":2,"l":2},"a":{"a":0,"k":[37.53,43.53,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.61,-3.511],[0.08,-0.38],[0.069,-0.28],[0.03,-0.1],[2.54,-3.51],[2.45,-1.981],[0.639,-0.45],[1.029,-0.591],[0.66,-0.32],[0.68,-0.28],[0.861,-0.28],[0.77,-0.189],[0.281,-0.069],[2.509,0],[0,0],[5.781,12],[-2.75,7.73],[-4.95,4.051],[-2.63,2.12],[-1.01,1.029],[-0.29,0.381],[0.06,1.44],[0.179,1.27],[-1,0.109],[-0.39,-0.201],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.13,-0.131],[-0.069,-0.11],[0,-0.411],[0,0],[-0.029,-0.409],[-0.02,-0.199],[-0.02,-0.159],[-0.09,-0.29],[-0.05,-0.14],[-0.04,-0.091],[-0.071,-0.109],[-0.09,-0.111],[-0.031,-0.04],[-0.55,-0.549],[-0.139,-0.141],[-2.41,-1.94],[-4.18,-5.951],[-0.83,-2.4],[-0.071,-0.241],[-0.05,-0.21],[-0.17,-0.9]],"o":[[-0.06,0.38],[-0.059,0.28],[-0.021,0.09],[-1.061,4.23],[-1.861,2.55],[-0.611,0.49],[-0.971,0.68],[-0.641,0.359],[-0.66,0.321],[-0.84,0.34],[-0.759,0.241],[-0.28,0.07],[-2.45,0.531],[0,0],[-13.32,0],[-3.54,-7.34],[2.18,-6.091],[2.62,-2.139],[2.72,-2.19],[0.551,-0.56],[1.03,-1.369],[-0.121,-2.79],[-0.161,-1.17],[0.361,-0.06],[0,0],[0,0],[0,0],[0,0],[0,0],[0.15,0.091],[0.091,0.09],[0.221,0.33],[0,0],[0,0.38],[0.011,0.201],[0.02,0.15],[0.04,0.301],[0.049,0.149],[0.04,0.09],[0.05,0.119],[0.059,0.12],[0.021,0.04],[0.279,0.37],[0.12,0.13],[1.02,0.98],[5.571,4.48],[1.461,2.089],[0.08,0.23],[0.069,0.21],[0.26,0.88],[0.679,3.5]],"v":[[34.92,12.91],[34.7,14.051],[34.511,14.889],[34.441,15.18],[28.941,26.88],[22.441,33.721],[20.561,35.139],[17.561,37.04],[15.62,38.059],[13.62,38.96],[11.07,39.889],[8.78,40.529],[7.95,40.729],[0.481,41.529],[0.45,41.529],[-31.09,21.699],[-32.78,-1.6],[-21.46,-16.561],[-13.44,-22.771],[-8.11,-27.41],[-6.9,-28.79],[-5.809,-33.45],[-6.269,-39.26],[-4.65,-41.469],[-3.51,-41.26],[0.45,-39.191],[0.481,-39.18],[0.481,-39.171],[5,-36.611],[5.71,-36.21],[6.13,-35.889],[6.38,-35.59],[6.721,-34.469],[6.721,-33.43],[6.75,-32.251],[6.8,-31.65],[6.86,-31.191],[7.061,-30.299],[7.21,-29.861],[7.33,-29.579],[7.521,-29.23],[7.74,-28.889],[7.811,-28.771],[9,-27.421],[9.4,-27.01],[14.36,-22.751],[30.3,-8.51],[33.74,-1.73],[33.971,-1.029],[34.16,-0.4],[34.811,2.27]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.572549019608,0.478431402468,0.839215746113,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":[37.53,43.53],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":18,"ty":3,"nm":"null-foot-leg-right ","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":216,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":225,"s":[-16]},{"t":234,"s":[0]}],"ix":10},"p":{"a":0,"k":[104.625,119.5,0],"ix":2,"l":2},"a":{"a":0,"k":[14.625,29.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"foot-right ","parent":18,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":106,"s":[-16.958]},{"t":112,"s":[0]}],"ix":10},"p":{"a":0,"k":[12.563,62.71,0],"ix":2,"l":2},"a":{"a":0,"k":[3.168,10.693,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,-4.229],[0,4.229],[5.063,0]],"o":[[0,4.229],[0,-4.229],[-5.064,0]],"v":[[-9.168,1.714],[9.168,1.714],[0,-5.943]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.572549019608,0.478431402468,0.839215746113,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":[11.168,7.944],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"leg-right ","parent":18,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[14.726,61.506,0],"ix":2,"l":2},"a":{"a":0,"k":[4.042,31.23,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":[[-2.628,14.816],[2.628,14.816],[2.628,-14.816],[-2.628,-14.816]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.572549019608,0.478431402468,0.839215746113,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":[4.042,16.23],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":21,"ty":3,"nm":"null-foot-leg-left","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":234,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":243,"s":[16]},{"t":252,"s":[0]}],"ix":10},"p":{"a":0,"k":[76.125,119.75,0],"ix":2,"l":2},"a":{"a":0,"k":[-13.706,29.818,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"foot-left ","parent":21,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":115,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":122,"s":[14]},{"t":128,"s":[0]}],"ix":10},"p":{"a":0,"k":[-11.138,62.21,0],"ix":2,"l":2},"a":{"a":0,"k":[19.667,10.193,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,-4.229],[0,4.229],[-5.064,0]],"o":[[0,4.229],[0,-4.229],[5.063,0]],"v":[[9.167,1.714],[-9.167,1.714],[0,-5.943]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.572549019608,0.478431402468,0.839215746113,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":[11.167,7.944],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"leg-left ","parent":21,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-13.8,46.604,0],"ix":2,"l":2},"a":{"a":0,"k":[4.041,16.327,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":[[2.627,14.913],[-2.627,14.913],[-2.627,-14.913],[2.627,-14.913]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.572549019608,0.478431402468,0.839215746113,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":[4.041,16.327],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"feather-right ","parent":11,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[2.257,-40.214,0],"ix":2,"l":2},"a":{"a":0,"k":[4.979,16.819,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":[[-1.92,-1.305],[-0.994,2.399],[-2.288,2.372],[4.027,-4.656],[0.654,-1.84]],"o":[[0.396,-1.953],[2.156,-5.198],[-2.176,0.596],[-2.233,2.583],[1.92,1.304]],"v":[[-1.844,8.944],[0.169,2.347],[7.605,-8.944],[-3.521,-2.013],[-7.605,5.031]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.901960844152,0.803921628466,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":[9.604,10.944],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"feather-left ","parent":11,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.563,-41.523,0],"ix":2,"l":2},"a":{"a":0,"k":[9.913,18.048,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":[[1.773,0.237],[1.134,3.207],[1.239,1.692],[-2.752,-3.696],[0.074,-1.377]],"o":[[-0.114,-2.056],[-1.171,-3.316],[1.418,0.498],[3.356,4.509],[-1.773,-0.236]],"v":[[0.059,7.463],[-1.565,-0.649],[-5.538,-8.173],[2.182,-2.518],[5.378,8.173]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.901960844152,0.803921628466,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":[7.538,10.173],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":"feather-center ","parent":11,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1.25,-36.84,0],"ix":2,"l":2},"a":{"a":0,"k":[4.789,33.995,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":[[1.865,0.364],[-0.623,5.891],[-1.236,4.546],[-0.391,-6.65],[0.616,-4.418]],"o":[[-0.218,-4.542],[0.653,-6.176],[1.225,4.483],[0.367,6.262],[-1.865,-0.364]],"v":[[-3.197,15.403],[-2.745,-0.342],[0.286,-16.495],[3.048,0.332],[2.4,16.495]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.294117647059,0.290196078431,0.560784313725,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.901960844152,0.803921628466,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":[5.414,18.495],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":"floor ","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[89.799,153.743,0],"ix":2,"l":2},"a":{"a":0,"k":[48.548,6.287,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,-3.334],[26.675,0],[0,3.334],[-26.674,0]],"o":[[0,3.334],[-26.674,0],[0,-3.334],[26.675,0]],"v":[[48.298,0],[0,6.037],[-48.298,0],[0,-6.037]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.921568687289,0.921568687289,0.921568687289,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":[48.548,6.287],"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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}],"markers":[{"tm":75,"cm":"connecting-start","dr":0},{"tm":165,"cm":"connecting-end","dr":0},{"tm":255,"cm":"connected-start","dr":0},{"tm":290,"cm":"connected-end","dr":0},{"tm":297,"cm":"disconnection-start","dr":0},{"tm":341,"cm":"disconnection-end","dr":0},{"tm":378,"cm":"failed-start","dr":0},{"tm":433,"cm":"failed-end","dr":0}]} \ No newline at end of file diff --git a/crypto_plugins/flutter_libepiccash b/crypto_plugins/flutter_libepiccash index f677dec0b..2de3fa045 160000 --- a/crypto_plugins/flutter_libepiccash +++ b/crypto_plugins/flutter_libepiccash @@ -1 +1 @@ -Subproject commit f677dec0b34d3f9fe8fce2bc8ff5c508c3f3bb9a +Subproject commit 2de3fa0459ac29361d65a86883e1d0648e6a4b1a diff --git a/crypto_plugins/flutter_liblelantus b/crypto_plugins/flutter_liblelantus index 9cd241b5e..1f8fde935 160000 --- a/crypto_plugins/flutter_liblelantus +++ b/crypto_plugins/flutter_liblelantus @@ -1 +1 @@ -Subproject commit 9cd241b5ea142e21c01dd7639b42603281c43287 +Subproject commit 1f8fde935bbb23585477b0cb884bee9be6d12a87 diff --git a/crypto_plugins/flutter_libmonero b/crypto_plugins/flutter_libmonero index e48952185..8a46a5d09 160000 --- a/crypto_plugins/flutter_libmonero +++ b/crypto_plugins/flutter_libmonero @@ -1 +1 @@ -Subproject commit e48952185556a10f182184fd572bcb04365f5831 +Subproject commit 8a46a5d0984cf7fbc1ce5d77cbb74dc6933da59c diff --git a/crypto_plugins/tor b/crypto_plugins/tor deleted file mode 160000 index a819223b2..000000000 --- a/crypto_plugins/tor +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a819223b23e9fa1d76bde82ed9109651e96f2ad3 diff --git a/lib/electrumx_rpc/electrumx.dart b/lib/electrumx_rpc/electrumx.dart index 292679342..dc07890cf 100644 --- a/lib/electrumx_rpc/electrumx.dart +++ b/lib/electrumx_rpc/electrumx.dart @@ -187,8 +187,8 @@ class ElectrumX { void _checkRpcClient() { // If we're supposed to use Tor... if (_prefs.useTor) { - // But Tor isn't enabled... - if (!_torService.enabled) { + // But Tor isn't running... + if (_torService.status != TorConnectionStatus.connected) { // And the killswitch isn't set... if (!_prefs.torKillSwitch) { // Then we'll just proceed and connect to ElectrumX through clearnet at the bottom of this function. @@ -203,7 +203,7 @@ class ElectrumX { } } else { // Get the proxy info from the TorService. - final proxyInfo = _torService.proxyInfo; + final proxyInfo = _torService.getProxyInfo(); if (currentFailoverIndex == -1) { _rpcClient ??= JsonRPC( diff --git a/lib/main.dart b/lib/main.dart index 9d9b3e879..dbab8bbb4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -173,7 +173,9 @@ void main() async { // Some refactoring will need to be done here to make sure we don't make any // network calls before starting up tor if (Prefs.instance.useTor) { - TorService.sharedInstance.init(); + TorService.sharedInstance.init( + torDataDirPath: (await StackFileSystem.applicationTorDirectory()).path, + ); await TorService.sharedInstance.start(); } diff --git a/lib/pages/buy_view/buy_view.dart b/lib/pages/buy_view/buy_view.dart index beeece754..e87fa3398 100644 --- a/lib/pages/buy_view/buy_view.dart +++ b/lib/pages/buy_view/buy_view.dart @@ -12,10 +12,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; import 'package:stackwallet/pages/buy_view/buy_form.dart'; -import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/services/event_bus/events/global/tor_connection_status_changed_event.dart'; +import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; +import 'package:stackwallet/widgets/tor_subscription.dart'; class BuyView extends ConsumerStatefulWidget { const BuyView({ @@ -36,18 +38,16 @@ class BuyView extends ConsumerStatefulWidget { class _BuyViewState extends ConsumerState { Coin? coin; EthContract? tokenContract; - late bool torEnabled = false; + + late bool torEnabled; @override void initState() { coin = widget.coin; tokenContract = widget.tokenContract; - WidgetsBinding.instance.addPostFrameCallback((_) async { - setState(() { - torEnabled = ref.read(prefsChangeNotifierProvider).useTor; - }); - }); + torEnabled = + ref.read(pTorService).status != TorConnectionStatus.disconnected; super.initState(); } @@ -56,35 +56,42 @@ class _BuyViewState extends ConsumerState { Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); - return Stack( - children: [ - SafeArea( - child: Padding( - padding: const EdgeInsets.only( - left: 16, - right: 16, - top: 16, - ), - child: BuyForm( - coin: coin, - tokenContract: tokenContract, + return TorSubscription( + onTorStatusChanged: (status) { + setState(() { + torEnabled = status != TorConnectionStatus.disconnected; + }); + }, + child: Stack( + children: [ + SafeArea( + child: Padding( + padding: const EdgeInsets.only( + left: 16, + right: 16, + top: 16, + ), + child: BuyForm( + coin: coin, + tokenContract: tokenContract, + ), ), ), - ), - if (torEnabled) - Container( - color: Theme.of(context) - .extension()! - .overlay - .withOpacity(0.7), - height: MediaQuery.of(context).size.height, - width: MediaQuery.of(context).size.width, - child: const StackDialog( - title: "Tor is enabled", - message: "Purchasing not available while Tor is enabled", + if (torEnabled) + Container( + color: Theme.of(context) + .extension()! + .overlay + .withOpacity(0.7), + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + child: const StackDialog( + title: "Tor is enabled", + message: "Purchasing not available while Tor is enabled", + ), ), - ), - ], + ], + ), ); } } diff --git a/lib/pages/ordinals/ordinal_details_view.dart b/lib/pages/ordinals/ordinal_details_view.dart index 17a518bf9..b0e478535 100644 --- a/lib/pages/ordinals/ordinal_details_view.dart +++ b/lib/pages/ordinals/ordinal_details_view.dart @@ -12,6 +12,7 @@ import 'package:stackwallet/models/isar/ordinal.dart'; import 'package:stackwallet/networking/http.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/providers/db/main_db_provider.dart'; +import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/themes/stack_colors.dart'; @@ -20,7 +21,6 @@ import 'package:stackwallet/utilities/amount/amount_formatter.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; -import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/background.dart'; @@ -219,7 +219,7 @@ class _DetailsItemWCopy extends StatelessWidget { } } -class _OrdinalImageGroup extends StatelessWidget { +class _OrdinalImageGroup extends ConsumerWidget { const _OrdinalImageGroup({ Key? key, required this.walletId, @@ -231,13 +231,14 @@ class _OrdinalImageGroup extends StatelessWidget { static const _spacing = 12.0; - Future _savePngToFile() async { + Future _savePngToFile(WidgetRef ref) async { HTTP client = HTTP(); final response = await client.get( url: Uri.parse(ordinal.content), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: ref.read(prefsChangeNotifierProvider).useTor + ? ref.read(pTorService).getProxyInfo() + : null, ); if (response.code != 200) { @@ -268,7 +269,7 @@ class _OrdinalImageGroup extends StatelessWidget { } @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, @@ -318,7 +319,7 @@ class _OrdinalImageGroup extends StatelessWidget { onPressed: () async { bool didError = false; final filePath = await showLoading( - whileFuture: _savePngToFile(), + whileFuture: _savePngToFile(ref), context: context, isDesktop: true, message: "Saving ordinal image", diff --git a/lib/pages/settings_views/global_settings_view/about_view.dart b/lib/pages/settings_views/global_settings_view/about_view.dart index 0d3e8d811..1c00b2891 100644 --- a/lib/pages/settings_views/global_settings_view/about_view.dart +++ b/lib/pages/settings_views/global_settings_view/about_view.dart @@ -50,8 +50,9 @@ Future doesCommitExist( final commitQuery = await client.get( url: uri, headers: {'Content-Type': 'application/json'}, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); final response = jsonDecode(commitQuery.body.toString()); @@ -89,8 +90,9 @@ Future isHeadCommit( final commitQuery = await client.get( url: uri, headers: {'Content-Type': 'application/json'}, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); final response = jsonDecode(commitQuery.body.toString()); diff --git a/lib/pages/settings_views/global_settings_view/tor_settings/tor_settings_view.dart b/lib/pages/settings_views/global_settings_view/tor_settings/tor_settings_view.dart index 097a68b93..a395d3897 100644 --- a/lib/pages/settings_views/global_settings_view/tor_settings/tor_settings_view.dart +++ b/lib/pages/settings_views/global_settings_view/tor_settings/tor_settings_view.dart @@ -13,6 +13,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:lottie/lottie.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/services/event_bus/events/global/tor_connection_status_changed_event.dart'; import 'package:stackwallet/services/tor_service.dart'; @@ -20,6 +21,7 @@ import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/logger.dart'; +import 'package:stackwallet/utilities/stack_file_system.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; @@ -31,7 +33,9 @@ import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/tor_subscription.dart'; class TorSettingsView extends ConsumerStatefulWidget { - const TorSettingsView({Key? key}) : super(key: key); + const TorSettingsView({ + Key? key, + }) : super(key: key); static const String routeName = "/torSettings"; @@ -71,7 +75,7 @@ class _TorSettingsViewState extends ConsumerState { useSafeArea: false, barrierDismissible: true, builder: (context) { - return const StackDialog( + return StackDialog( title: "What is Tor?", message: "Short for \"The Onion Router\", is an open-source software that enables internet communication" @@ -79,6 +83,7 @@ class _TorSettingsViewState extends ConsumerState { " to obscure the origin and destination of data.", rightButton: SecondaryButton( label: "Close", + onPressed: Navigator.of(context).pop, ), ); }, @@ -98,7 +103,7 @@ class _TorSettingsViewState extends ConsumerState { children: [ Padding( padding: EdgeInsets.all(10.0), - child: TorIcon(), + child: TorAnimatedButton(), ), ], ), @@ -140,7 +145,7 @@ class _TorSettingsViewState extends ConsumerState { useSafeArea: false, barrierDismissible: true, builder: (context) { - return const StackDialog( + return StackDialog( title: "What is Tor killswitch?", message: "A security feature that protects your information from accidental exposure by" @@ -148,6 +153,8 @@ class _TorSettingsViewState extends ConsumerState { " connection is disrupted or compromised.", rightButton: SecondaryButton( label: "Close", + onPressed: + Navigator.of(context).pop, ), ); }, @@ -194,48 +201,19 @@ class _TorSettingsViewState extends ConsumerState { } } -class TorIcon extends ConsumerStatefulWidget { - const TorIcon({super.key}); +class TorAnimatedButton extends ConsumerStatefulWidget { + const TorAnimatedButton({super.key}); @override - ConsumerState createState() => _TorIconState(); + ConsumerState createState() => _TorAnimatedButtonState(); } -class _TorIconState extends ConsumerState { +class _TorAnimatedButtonState extends ConsumerState + with SingleTickerProviderStateMixin { + late final AnimationController controller1; + late TorConnectionStatus _status; - Color _color( - TorConnectionStatus status, - StackColors colors, - ) { - switch (status) { - case TorConnectionStatus.disconnected: - return colors.textSubtitle3; - - case TorConnectionStatus.connected: - return colors.accentColorGreen; - - case TorConnectionStatus.connecting: - return colors.accentColorYellow; - } - } - - String _label( - TorConnectionStatus status, - StackColors colors, - ) { - switch (status) { - case TorConnectionStatus.disconnected: - return "CONNECT"; - - case TorConnectionStatus.connected: - return "STOP"; - - case TorConnectionStatus.connecting: - return "CONNECTING"; - } - } - bool _tapLock = false; Future onTap() async { @@ -268,22 +246,106 @@ class _TorIconState extends ConsumerState { } } + Future _playConnecting() async { + await _play( + from: "connecting-start", + to: "connecting-end", + repeat: true, + ); + } + + Future _playConnectingDone() async { + await _play( + from: "connecting-end", + to: "connected-start", + repeat: false, + ); + } + + Future _playConnected() async { + await _play( + from: "connected-start", + to: "connected-end", + repeat: true, + ); + } + + Future _playDisconnect() async { + await _play( + from: "disconnection-start", + to: "disconnection-end", + repeat: false, + ); + controller1.reset(); + } + + Future _play({ + required String from, + required String to, + required bool repeat, + }) async { + final composition = await _completer.future; + final start = composition.getMarker(from)!.start; + final end = composition.getMarker(to)!.start; + + controller1.value = start; + + if (repeat) { + await controller1.repeat( + min: start, + max: end, + period: composition.duration * (end - start), + ); + } else { + await controller1.animateTo( + end, + duration: composition.duration * (end - start), + ); + } + } + + late Completer _completer; + @override void initState() { - _status = ref.read(pTorService).enabled - ? TorConnectionStatus.connected - : TorConnectionStatus.disconnected; + controller1 = AnimationController(vsync: this); + + _status = ref.read(pTorService).status; + + _completer = Completer(); super.initState(); } + @override + void dispose() { + controller1.dispose(); + + super.dispose(); + } + @override Widget build(BuildContext context) { + // TODO: modify size (waiting for updated onion lottie animation file) + final width = MediaQuery.of(context).size.width / 1.5; + return TorSubscription( - onTorStatusChanged: (status) { - setState(() { - _status = status; - }); + onTorStatusChanged: (status) async { + _status = status; + switch (_status) { + case TorConnectionStatus.disconnected: + await _playDisconnect(); + break; + + case TorConnectionStatus.connected: + await _playConnectingDone(); + await _playConnected(); + break; + + case TorConnectionStatus.connecting: + await _playConnecting(); + break; + } }, child: ConditionalParent( condition: _status != TorConnectionStatus.connecting, @@ -291,32 +353,29 @@ class _TorIconState extends ConsumerState { onTap: onTap, child: child, ), - child: SizedBox( - width: 220, - height: 220, - child: Stack( - alignment: AlignmentDirectional.center, - children: [ - SvgPicture.asset( - Assets.svg.tor, - color: _color( - _status, - Theme.of(context).extension()!, - ), - width: 200, - height: 200, + child: Column( + children: [ + SizedBox( + width: width, + child: Lottie.asset( + Assets.lottie.onionTor, + controller: controller1, + width: width, + // height: width, + onLoaded: (composition) { + _completer.complete(composition); + controller1.duration = composition.duration; + + if (_status == TorConnectionStatus.connected) { + _playConnected(); + } else if (_status == TorConnectionStatus.connecting) { + _playConnecting(); + } + }, ), - Text( - _label( - _status, - Theme.of(context).extension()!, - ), - style: STextStyles.smallMed14(context).copyWith( - color: Theme.of(context).extension()!.popupBG, - ), - ), - ], - ), + ), + const UpperCaseTorText(), + ], ), ), ); @@ -399,9 +458,7 @@ class _TorButtonState extends ConsumerState { @override void initState() { - _status = ref.read(pTorService).enabled - ? TorConnectionStatus.connected - : TorConnectionStatus.disconnected; + _status = ref.read(pTorService).status; super.initState(); } @@ -447,6 +504,78 @@ class _TorButtonState extends ConsumerState { } } +class UpperCaseTorText extends ConsumerStatefulWidget { + const UpperCaseTorText({super.key}); + + @override + ConsumerState createState() => _UpperCaseTorTextState(); +} + +class _UpperCaseTorTextState extends ConsumerState { + late TorConnectionStatus _status; + + Color _color( + TorConnectionStatus status, + StackColors colors, + ) { + switch (status) { + case TorConnectionStatus.disconnected: + return colors.textSubtitle3; + + case TorConnectionStatus.connected: + return colors.accentColorGreen; + + case TorConnectionStatus.connecting: + return colors.accentColorYellow; + } + } + + String _label( + TorConnectionStatus status, + ) { + switch (status) { + case TorConnectionStatus.disconnected: + return "CONNECT"; + + case TorConnectionStatus.connected: + return "STOP"; + + case TorConnectionStatus.connecting: + return "CONNECTING"; + } + } + + @override + void initState() { + _status = ref.read(pTorService).status; + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return TorSubscription( + onTorStatusChanged: (status) { + setState(() { + _status = status; + }); + }, + child: Text( + _label( + _status, + ), + style: STextStyles.pageTitleH2( + context, + ).copyWith( + color: _color( + _status, + Theme.of(context).extension()!, + ), + ), + )); + } +} + /// Connect to the Tor network. /// /// This method is called when the user taps the "Connect" button. @@ -455,11 +584,11 @@ class _TorButtonState extends ConsumerState { /// /// Returns a Future that completes when the Tor service has started. Future _connectTor(WidgetRef ref, BuildContext context) async { - // Init the Tor service if it hasn't already been. - ref.read(pTorService).init(); - - // Start the Tor service. try { + // Init the Tor service if it hasn't already been. + final torDir = await StackFileSystem.applicationTorDirectory(); + ref.read(pTorService).init(torDataDirPath: torDir.path); + // Start the Tor service. await ref.read(pTorService).start(); // Toggle the useTor preference on success. @@ -485,7 +614,7 @@ Future _connectTor(WidgetRef ref, BuildContext context) async { Future _disconnectTor(WidgetRef ref, BuildContext context) async { // Stop the Tor service. try { - await ref.read(pTorService).stop(); + await ref.read(pTorService).disable(); // Toggle the useTor preference on success. ref.read(prefsChangeNotifierProvider).useTor = false; diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart index 48f805691..ad91b3b07 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart @@ -36,6 +36,7 @@ import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; +import 'package:stackwallet/utilities/stack_file_system.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/animated_text.dart'; @@ -48,6 +49,7 @@ import 'package:stackwallet/widgets/progress_bar.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; +import 'package:stackwallet/widgets/tor_subscription.dart'; import 'package:tuple/tuple.dart'; import 'package:wakelock/wakelock.dart'; @@ -98,10 +100,6 @@ class _WalletNetworkSettingsViewState /// The current status of the Tor connection. late TorConnectionStatus _torConnectionStatus; - /// The subscription to the TorConnectionStatusChangedEvent. - late final StreamSubscription - _torConnectionStatusSubscription; - Future _attemptRescan() async { if (!Platform.isLinux) await Wakelock.enable(); @@ -280,22 +278,7 @@ class _WalletNetworkSettingsViewState // ); // Initialize the TorConnectionStatus. - _torConnectionStatus = ref.read(pTorService).enabled - ? TorConnectionStatus.connected - : TorConnectionStatus.disconnected; - - // Subscribe to the TorConnectionStatusChangedEvent. - _torConnectionStatusSubscription = - eventBus.on().listen( - (event) async { - // Rebuild the widget. - setState(() { - _torConnectionStatus = event.newStatus; - }); - - // TODO implement spinner or animations and control from here - }, - ); + _torConnectionStatus = ref.read(pTorService).status; super.initState(); } @@ -306,7 +289,6 @@ class _WalletNetworkSettingsViewState _syncStatusSubscription.cancel(); _refreshSubscription.cancel(); _blocksRemainingSubscription?.cancel(); - _torConnectionStatusSubscription.cancel(); super.dispose(); } @@ -793,7 +775,7 @@ class _WalletNetworkSettingsViewState onTap: () async { // Stop the Tor service. try { - await ref.read(pTorService).stop(); + await ref.read(pTorService).disable(); // Toggle the useTor preference on success. ref.read(prefsChangeNotifierProvider).useTor = false; @@ -813,11 +795,12 @@ class _WalletNetworkSettingsViewState prefsChangeNotifierProvider.select((value) => value.useTor))) GestureDetector( onTap: () async { - // Init the Tor service if it hasn't already been. - ref.read(pTorService).init(); - - // Start the Tor service. try { + // Init the Tor service if it hasn't already been. + final torDir = + await StackFileSystem.applicationTorDirectory(); + ref.read(pTorService).init(torDataDirPath: torDir.path); + // Start the Tor service. await ref.read(pTorService).start(); // Toggle the useTor preference on success. @@ -827,6 +810,7 @@ class _WalletNetworkSettingsViewState "Error starting tor: $e\n$s", level: LogLevel.Error, ); + // TODO: show dialog with error message } }, child: Text( @@ -896,35 +880,46 @@ class _WalletNetworkSettingsViewState SizedBox( width: _boxPadding, ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Tor status", - style: STextStyles.desktopTextExtraExtraSmall(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textDark, - ), - ), - if (_torConnectionStatus == TorConnectionStatus.connected) + TorSubscription( + onTorStatusChanged: (status) { + setState(() { + _torConnectionStatus = status; + }); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ Text( - "Connected", - style: STextStyles.desktopTextExtraExtraSmall(context), + "Tor status", + style: STextStyles.desktopTextExtraExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark, + ), ), - if (_torConnectionStatus == TorConnectionStatus.connecting) - Text( - "Connecting...", - style: STextStyles.desktopTextExtraExtraSmall(context), - ), - if (_torConnectionStatus == - TorConnectionStatus.disconnected) - Text( - "Disconnected", - style: STextStyles.desktopTextExtraExtraSmall(context), - ), - ], + if (_torConnectionStatus == TorConnectionStatus.connected) + Text( + "Connected", + style: + STextStyles.desktopTextExtraExtraSmall(context), + ), + if (_torConnectionStatus == + TorConnectionStatus.connecting) + Text( + "Connecting...", + style: + STextStyles.desktopTextExtraExtraSmall(context), + ), + if (_torConnectionStatus == + TorConnectionStatus.disconnected) + Text( + "Disconnected", + style: + STextStyles.desktopTextExtraExtraSmall(context), + ), + ], + ), ), ], ), diff --git a/lib/pages_desktop_specific/desktop_buy/desktop_buy_view.dart b/lib/pages_desktop_specific/desktop_buy/desktop_buy_view.dart index 8827641fa..b9c00c762 100644 --- a/lib/pages_desktop_specific/desktop_buy/desktop_buy_view.dart +++ b/lib/pages_desktop_specific/desktop_buy/desktop_buy_view.dart @@ -11,13 +11,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/buy_view/buy_form.dart'; -import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/services/event_bus/events/global/tor_connection_status_changed_event.dart'; +import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; +import 'package:stackwallet/widgets/tor_subscription.dart'; class DesktopBuyView extends ConsumerStatefulWidget { const DesktopBuyView({Key? key}) : super(key: key); @@ -29,117 +31,121 @@ class DesktopBuyView extends ConsumerStatefulWidget { } class _DesktopBuyViewState extends ConsumerState { - late bool torEnabled = false; + late bool torEnabled; @override void initState() { - WidgetsBinding.instance.addPostFrameCallback((_) async { - setState(() { - torEnabled = ref.read(prefsChangeNotifierProvider).useTor; - }); - }); + torEnabled = + ref.read(pTorService).status != TorConnectionStatus.disconnected; super.initState(); } @override Widget build(BuildContext context) { - return Stack( - children: [ - DesktopScaffold( - appBar: DesktopAppBar( - isCompactHeight: true, - leading: Padding( - padding: const EdgeInsets.only( - left: 24, + return TorSubscription( + onTorStatusChanged: (status) { + setState(() { + torEnabled = status != TorConnectionStatus.disconnected; + }); + }, + child: Stack( + children: [ + DesktopScaffold( + appBar: DesktopAppBar( + isCompactHeight: true, + leading: Padding( + padding: const EdgeInsets.only( + left: 24, + ), + child: Text( + "Buy crypto", + style: STextStyles.desktopH3(context), + ), ), - child: Text( - "Buy crypto", - style: STextStyles.desktopH3(context), + ), + body: const Padding( + padding: EdgeInsets.only( + left: 24, + right: 24, + bottom: 24, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 16, + ), + RoundedWhiteContainer( + padding: EdgeInsets.all(24), + child: BuyForm(), + ), + ], + ), + ), + SizedBox( + width: 16, + ), + // Expanded( + // child: Row( + // children: const [ + // Expanded( + // child: DesktopTradeHistory(), + // ), + // ], + // ), + // ), + ], ), ), ), - body: Padding( - padding: const EdgeInsets.only( - left: 24, - right: 24, - bottom: 24, - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( + if (torEnabled) + Container( + color: Theme.of(context) + .extension()! + .overlay + .withOpacity(0.7), + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + child: DesktopDialog( + maxHeight: 200, + maxWidth: 350, + child: Padding( + padding: const EdgeInsets.all( + 15.0, + ), child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - SizedBox( - height: 16, + // crossAxisAlignment: CrossAxisAlignment.center, + // mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Tor is enabled", + textAlign: TextAlign.center, + style: STextStyles.pageTitleH1(context), ), - RoundedWhiteContainer( - padding: EdgeInsets.all(24), - child: BuyForm(), + const SizedBox( + height: 30, + ), + Text( + "Purchasing not available while Tor is enabled", + textAlign: TextAlign.center, + style: STextStyles.desktopTextMedium(context).copyWith( + color: Theme.of(context) + .extension()! + .infoItemLabel, + ), ), ], ), ), - const SizedBox( - width: 16, - ), - // Expanded( - // child: Row( - // children: const [ - // Expanded( - // child: DesktopTradeHistory(), - // ), - // ], - // ), - // ), - ], - ), - ), - ), - if (torEnabled) - Container( - color: Theme.of(context) - .extension()! - .overlay - .withOpacity(0.7), - height: MediaQuery.of(context).size.height, - width: MediaQuery.of(context).size.width, - child: DesktopDialog( - maxHeight: 200, - maxWidth: 350, - child: Padding( - padding: const EdgeInsets.all( - 15.0, - ), - child: Column( - // crossAxisAlignment: CrossAxisAlignment.center, - // mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Tor is enabled", - textAlign: TextAlign.center, - style: STextStyles.pageTitleH1(context), - ), - const SizedBox( - height: 30, - ), - Text( - "Purchasing not available while Tor is enabled", - textAlign: TextAlign.center, - style: STextStyles.desktopTextMedium(context).copyWith( - color: Theme.of(context) - .extension()! - .infoItemLabel, - ), - ), - ], - ), ), ), - ), - ], + ], + ), ); } } diff --git a/lib/pages_desktop_specific/ordinals/desktop_ordinal_details_view.dart b/lib/pages_desktop_specific/ordinals/desktop_ordinal_details_view.dart index f1c6093aa..44135c3b2 100644 --- a/lib/pages_desktop_specific/ordinals/desktop_ordinal_details_view.dart +++ b/lib/pages_desktop_specific/ordinals/desktop_ordinal_details_view.dart @@ -56,8 +56,9 @@ class _DesktopOrdinalDetailsViewState final response = await client.get( url: Uri.parse(widget.ordinal.content), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code != 200) { diff --git a/lib/pages_desktop_specific/settings/settings_menu/tor_settings/tor_settings.dart b/lib/pages_desktop_specific/settings/settings_menu/tor_settings/tor_settings.dart index 212387035..ff507b79e 100644 --- a/lib/pages_desktop_specific/settings/settings_menu/tor_settings/tor_settings.dart +++ b/lib/pages_desktop_specific/settings/settings_menu/tor_settings/tor_settings.dart @@ -22,6 +22,7 @@ import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/logger.dart'; +import 'package:stackwallet/utilities/stack_file_system.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/custom_buttons/draggable_switch_button.dart'; @@ -59,11 +60,11 @@ class _TorSettingsState extends ConsumerState { width: 200, buttonHeight: ButtonHeight.m, onPressed: () async { - // Init the Tor service if it hasn't already been. - ref.read(pTorService).init(); - - // Start the Tor service. try { + // Init the Tor service if it hasn't already been. + final torDir = await StackFileSystem.applicationTorDirectory(); + ref.read(pTorService).init(torDataDirPath: torDir.path); + // Start the Tor service. await ref.read(pTorService).start(); // Toggle the useTor preference on success. @@ -73,6 +74,7 @@ class _TorSettingsState extends ConsumerState { "Error starting tor: $e\n$s", level: LogLevel.Error, ); + // TODO: show dialog with error message } }, ); @@ -93,7 +95,7 @@ class _TorSettingsState extends ConsumerState { onPressed: () async { // Stop the Tor service. try { - await ref.read(pTorService).stop(); + await ref.read(pTorService).disable(); // Toggle the useTor preference on success. ref.read(prefsChangeNotifierProvider).useTor = false; @@ -114,9 +116,7 @@ class _TorSettingsState extends ConsumerState { eventBus = GlobalEventBus.instance; // Set the initial Tor connection status. - _torConnectionStatus = ref.read(pTorService).enabled - ? TorConnectionStatus.connected - : TorConnectionStatus.disconnected; + _torConnectionStatus = ref.read(pTorService).status; // Subscribe to the TorConnectionStatusChangedEvent. _torConnectionStatusSubscription = @@ -219,8 +219,21 @@ class _TorSettingsState extends ConsumerState { children: [ Row( mainAxisAlignment: - MainAxisAlignment.end, + MainAxisAlignment + .spaceBetween, children: [ + Padding( + padding: + const EdgeInsets.only( + left: 32, + ), + child: Text( + "What is Tor?", + style: + STextStyles.desktopH2( + context), + ), + ), DesktopDialogCloseButton( onPressedOverride: () => Navigator.of(context) @@ -229,34 +242,24 @@ class _TorSettingsState extends ConsumerState { ], ), Padding( - padding: const EdgeInsets.all(20), - child: Column( - mainAxisSize: MainAxisSize.max, - children: [ - Text( - "What is Tor?", - style: - STextStyles.desktopH2( - context), - ), - const SizedBox( - height: 20, - ), - Text( - "Short for \"The Onion Router\", is an open-source software that enables internet communication" - " to remain anonymous by routing internet traffic through a series of layered nodes," - " to obscure the origin and destination of data.", - style: STextStyles - .desktopTextMedium( - context) - .copyWith( - color: Theme.of(context) - .extension< - StackColors>()! - .textDark3, - ), - ), - ], + padding: const EdgeInsets.only( + top: 12, + left: 32, + bottom: 32, + right: 32, + ), + child: Text( + "Short for \"The Onion Router\", is an open-source software that enables internet communication" + " to remain anonymous by routing internet traffic through a series of layered nodes," + " to obscure the origin and destination of data.", + style: STextStyles + .desktopTextMedium( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark3, + ), ), ), ], @@ -289,21 +292,25 @@ class _TorSettingsState extends ConsumerState { children: [ Row( children: [ - RichText( - textAlign: TextAlign.start, - text: TextSpan( - children: [ - TextSpan( - text: "Tor killswitch", - style: STextStyles.desktopTextExtraExtraSmall( - context) - .copyWith( - color: Theme.of(context) - .extension()! - .textDark), - ), - TextSpan( - text: "\nWhat is Tor killswitch?", + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Tor killswitch", + style: STextStyles.desktopTextExtraExtraSmall( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark), + ), + const SizedBox( + height: 8, + ), + RichText( + textAlign: TextAlign.start, + text: TextSpan( + text: "What is Tor killswitch?", style: STextStyles.richLink(context).copyWith( fontSize: 14, ), @@ -321,8 +328,20 @@ class _TorSettingsState extends ConsumerState { children: [ Row( mainAxisAlignment: - MainAxisAlignment.end, + MainAxisAlignment + .spaceBetween, children: [ + Padding( + padding: + const EdgeInsets.only( + left: 32, + ), + child: Text( + "What is Tor killswitch?", + style: STextStyles + .desktopH2(context), + ), + ), DesktopDialogCloseButton( onPressedOverride: () => Navigator.of(context) @@ -332,35 +351,25 @@ class _TorSettingsState extends ConsumerState { ), Padding( padding: - const EdgeInsets.all(20), - child: Column( - mainAxisSize: - MainAxisSize.max, - children: [ - Text( - "What is Tor killswitch?", - style: STextStyles - .desktopH2(context), - ), - const SizedBox( - height: 20, - ), - Text( - "A security feature that protects your information from accidental exposure by" - " disconnecting your device from the Tor network if the" - " connection is disrupted or compromised.", - style: STextStyles - .desktopTextMedium( - context) - .copyWith( - color: Theme.of( - context) - .extension< - StackColors>()! - .textDark3, - ), - ), - ], + const EdgeInsets.only( + top: 12, + left: 32, + bottom: 32, + right: 32, + ), + child: Text( + "A security feature that protects your information from accidental exposure by" + " disconnecting your device from the Tor network if the" + " connection is disrupted or compromised.", + style: STextStyles + .desktopTextMedium( + context) + .copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .textDark3, + ), ), ), ], @@ -370,8 +379,8 @@ class _TorSettingsState extends ConsumerState { ); }, ), - ], - ), + ), + ], ), ], ), diff --git a/lib/services/buy/simplex/simplex_api.dart b/lib/services/buy/simplex/simplex_api.dart index 1b2d26e26..6ab2736e4 100644 --- a/lib/services/buy/simplex/simplex_api.dart +++ b/lib/services/buy/simplex/simplex_api.dart @@ -59,7 +59,7 @@ class SimplexAPI { url: url, headers: headers, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + Prefs.instance.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); if (res.code != 200) { throw Exception( @@ -125,7 +125,7 @@ class SimplexAPI { url: url, headers: headers, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + Prefs.instance.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); if (res.code != 200) { throw Exception( @@ -206,7 +206,7 @@ class SimplexAPI { url: url, headers: headers, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + Prefs.instance.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); if (res.code != 200) { throw Exception('getQuote exception: statusCode= ${res.code}'); @@ -313,7 +313,7 @@ class SimplexAPI { url: url, headers: headers, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + Prefs.instance.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); if (res.code != 200) { throw Exception('newOrder exception: statusCode= ${res.code}'); diff --git a/lib/services/coins/banano/banano_wallet.dart b/lib/services/coins/banano/banano_wallet.dart index 9f314f3a3..735336824 100644 --- a/lib/services/coins/banano/banano_wallet.dart +++ b/lib/services/coins/banano/banano_wallet.dart @@ -160,7 +160,7 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB { }, ), proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ) .then((client) { if (client.code == 200) { @@ -195,7 +195,7 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: balanceBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final balanceData = jsonDecode(balanceResponse.body); @@ -215,7 +215,7 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: infoBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final String frontier = @@ -270,7 +270,7 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: processBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final Map decoded = @@ -344,7 +344,7 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: body, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final data = jsonDecode(response.body); _balance = Balance( @@ -388,7 +388,7 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: infoBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final infoData = jsonDecode(infoResponse.body); @@ -408,7 +408,7 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: balanceBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final balanceData = jsonDecode(balanceResponse.body); @@ -483,7 +483,7 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: processBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final Map decoded = @@ -504,7 +504,7 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB { "count": "-1", }), proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final receivableData = await jsonDecode(receivableResponse.body); @@ -536,7 +536,7 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB { "count": "-1", }), proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final data = await jsonDecode(response.body); final transactions = @@ -858,7 +858,7 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB { }, ), proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); return response.code == 200; @@ -952,7 +952,7 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: infoBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final infoData = jsonDecode(infoResponse.body); diff --git a/lib/services/coins/nano/nano_wallet.dart b/lib/services/coins/nano/nano_wallet.dart index 56404ed1a..bf324a95d 100644 --- a/lib/services/coins/nano/nano_wallet.dart +++ b/lib/services/coins/nano/nano_wallet.dart @@ -169,7 +169,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB { }, ), proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ) .then((Response response) { if (response.code == 200) { @@ -204,7 +204,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: balanceBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final balanceData = jsonDecode(balanceResponse.body); @@ -224,7 +224,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: infoBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final String frontier = @@ -279,7 +279,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: processBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final Map decoded = @@ -349,7 +349,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: body, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final data = jsonDecode(response.body); _balance = Balance( @@ -393,7 +393,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: infoBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final infoData = jsonDecode(infoResponse.body); @@ -413,7 +413,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: balanceBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final balanceData = jsonDecode(balanceResponse.body); @@ -488,7 +488,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: processBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final Map decoded = @@ -509,7 +509,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB { "count": "-1", }), proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final receivableData = await jsonDecode(receivableResponse.body); @@ -541,7 +541,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB { "count": "-1", }), proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final data = await jsonDecode(response.body); final transactions = @@ -869,7 +869,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB { }, ), proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); return response.code == 200; @@ -963,7 +963,7 @@ class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB { headers: headers, body: infoBody, proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); final infoData = jsonDecode(infoResponse.body); diff --git a/lib/services/coins/tezos/tezos_wallet.dart b/lib/services/coins/tezos/tezos_wallet.dart index 130671264..fa5abc30e 100644 --- a/lib/services/coins/tezos/tezos_wallet.dart +++ b/lib/services/coins/tezos/tezos_wallet.dart @@ -245,7 +245,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB { var response = jsonDecode((await client.get( url: Uri.parse(api), proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, )) .body)[0]; double totalFees = response[4] as double; @@ -270,7 +270,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB { var response = jsonDecode((await client.get( url: Uri.parse(api), proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, )) .body); double totalFees = response[0][4] as double; @@ -509,9 +509,8 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB { var response = jsonDecode(await client .get( url: Uri.parse(balanceCall), - proxyInfo: Prefs.instance.useTor - ? TorService.sharedInstance.proxyInfo - : null, + proxyInfo: + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ) .then((value) => value.body)); Amount balanceInAmount = Amount( @@ -538,9 +537,8 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB { var response = jsonDecode(await client .get( url: Uri.parse(transactionsCall), - proxyInfo: Prefs.instance.useTor - ? TorService.sharedInstance.proxyInfo - : null, + proxyInfo: + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ) .then((value) => value.body)); List> txs = []; @@ -619,9 +617,8 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB { var jsonParsedResponse = jsonDecode(await client .get( url: Uri.parse(api), - proxyInfo: Prefs.instance.useTor - ? TorService.sharedInstance.proxyInfo - : null, + proxyInfo: + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ) .then((value) => value.body)); final int intHeight = int.parse(jsonParsedResponse["level"].toString()); @@ -707,7 +704,7 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB { url: Uri.parse( "${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/header/shell"), proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + _prefs.useTor ? TorService.sharedInstance.getProxyInfo() : null, ); return true; } catch (e) { diff --git a/lib/services/ethereum/ethereum_api.dart b/lib/services/ethereum/ethereum_api.dart index 19fa6b081..13e11f7ab 100644 --- a/lib/services/ethereum/ethereum_api.dart +++ b/lib/services/ethereum/ethereum_api.dart @@ -61,8 +61,9 @@ abstract class EthereumAPI { url: Uri.parse( "$stackBaseServer/export?addrs=$address&firstBlock=$firstBlock", ), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { @@ -184,8 +185,9 @@ abstract class EthereumAPI { url: Uri.parse( "$stackBaseServer/transactions?transactions=${txns.map((e) => e.hash).join(" ")}&raw=true", ), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { @@ -244,8 +246,9 @@ abstract class EthereumAPI { url: Uri.parse( "$stackBaseServer/transactions?transactions=${txids.join(" ")}", ), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { @@ -303,8 +306,9 @@ abstract class EthereumAPI { url: Uri.parse( "$stackBaseServer/export?addrs=$address&emitter=$tokenContractAddress&logs=true", ), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { @@ -437,8 +441,9 @@ abstract class EthereumAPI { ); final response = await client.get( url: uri, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { @@ -488,8 +493,9 @@ abstract class EthereumAPI { ); final response = await client.get( url: uri, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { @@ -535,8 +541,9 @@ abstract class EthereumAPI { url: Uri.parse( "$stackBaseServer/gas-prices", ), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { @@ -606,8 +613,9 @@ abstract class EthereumAPI { url: Uri.parse( "$stackBaseServer/tokens?addrs=$contractAddress&parts=all", ), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { @@ -675,8 +683,9 @@ abstract class EthereumAPI { url: Uri.parse( "$stackBaseServer/abis?addrs=$contractAddress&verbose=true", ), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { @@ -717,8 +726,9 @@ abstract class EthereumAPI { final response = await client.get( url: Uri.parse( "$stackBaseServer/state?addrs=$contractAddress&parts=proxy"), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { final json = jsonDecode(response.body); diff --git a/lib/services/exchange/change_now/change_now_api.dart b/lib/services/exchange/change_now/change_now_api.dart index d8b260495..b847482a4 100644 --- a/lib/services/exchange/change_now/change_now_api.dart +++ b/lib/services/exchange/change_now/change_now_api.dart @@ -60,8 +60,9 @@ class ChangeNowAPI { final response = await client.get( url: uri, headers: {'Content-Type': 'application/json'}, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); String? data; try { @@ -90,8 +91,9 @@ class ChangeNowAPI { // 'Content-Type': 'application/json', 'x-changenow-api-key': apiKey, }, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); final data = response.body; @@ -114,8 +116,9 @@ class ChangeNowAPI { url: uri, headers: {'Content-Type': 'application/json'}, body: jsonEncode(body), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); String? data; diff --git a/lib/services/exchange/majestic_bank/majestic_bank_api.dart b/lib/services/exchange/majestic_bank/majestic_bank_api.dart index d32209ae5..695bfeb08 100644 --- a/lib/services/exchange/majestic_bank/majestic_bank_api.dart +++ b/lib/services/exchange/majestic_bank/majestic_bank_api.dart @@ -49,8 +49,9 @@ class MajesticBankAPI { try { final response = await client.get( url: uri, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); code = response.code; diff --git a/lib/services/exchange/simpleswap/simpleswap_api.dart b/lib/services/exchange/simpleswap/simpleswap_api.dart index d52f8aa21..816c57a01 100644 --- a/lib/services/exchange/simpleswap/simpleswap_api.dart +++ b/lib/services/exchange/simpleswap/simpleswap_api.dart @@ -47,8 +47,9 @@ class SimpleSwapAPI { try { final response = await client.get( url: uri, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); code = response.code; @@ -74,8 +75,9 @@ class SimpleSwapAPI { url: uri, headers: {'Content-Type': 'application/json'}, body: jsonEncode(body), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { diff --git a/lib/services/exchange/trocador/trocador_api.dart b/lib/services/exchange/trocador/trocador_api.dart index 8dadfb499..ac01af5a4 100644 --- a/lib/services/exchange/trocador/trocador_api.dart +++ b/lib/services/exchange/trocador/trocador_api.dart @@ -52,8 +52,9 @@ abstract class TrocadorAPI { final response = await client.get( url: uri, headers: {'Content-Type': 'application/json'}, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); code = response.code; diff --git a/lib/services/litescribe_api.dart b/lib/services/litescribe_api.dart index ea4013457..65f1783d1 100644 --- a/lib/services/litescribe_api.dart +++ b/lib/services/litescribe_api.dart @@ -22,8 +22,9 @@ class LitescribeAPI { Future _getResponse(String endpoint) async { final response = await client.get( url: Uri.parse('$baseUrl$endpoint'), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { return LitescribeResponse(data: _validateJson(response.body)); diff --git a/lib/services/monkey_service.dart b/lib/services/monkey_service.dart index eb3687fcd..f6f804cb3 100644 --- a/lib/services/monkey_service.dart +++ b/lib/services/monkey_service.dart @@ -25,8 +25,9 @@ class MonKeyService { final response = await client.get( url: Uri.parse(url), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); if (response.code == 200) { diff --git a/lib/services/nano_api.dart b/lib/services/nano_api.dart index c0d194a31..e9035c8e9 100644 --- a/lib/services/nano_api.dart +++ b/lib/services/nano_api.dart @@ -31,8 +31,9 @@ class NanoAPI { "representative": "true", "account": account, }), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); final map = jsonDecode(response.body); @@ -124,8 +125,9 @@ class NanoAPI { "subtype": "change", "block": block, }), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); return jsonDecode(response.body); diff --git a/lib/services/price.dart b/lib/services/price.dart index a4ffff961..ce1a57301 100644 --- a/lib/services/price.dart +++ b/lib/services/price.dart @@ -107,8 +107,9 @@ class PriceAPI { final coinGeckoResponse = await client.get( url: uri, headers: {'Content-Type': 'application/json'}, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); final coinGeckoData = jsonDecode(coinGeckoResponse.body) as List; @@ -154,8 +155,9 @@ class PriceAPI { final response = await client.get( url: uri, headers: {'Content-Type': 'application/json'}, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); final json = jsonDecode(response.body) as List; @@ -195,8 +197,9 @@ class PriceAPI { final coinGeckoResponse = await client.get( url: uri, headers: {'Content-Type': 'application/json'}, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); final coinGeckoData = jsonDecode(coinGeckoResponse.body) as Map; diff --git a/lib/services/tor_service.dart b/lib/services/tor_service.dart index ead6ab5fa..c4e7a0117 100644 --- a/lib/services/tor_service.dart +++ b/lib/services/tor_service.dart @@ -10,33 +10,45 @@ final pTorService = Provider((_) => TorService.sharedInstance); class TorService { Tor? _tor; + String? _torDataDirPath; - /// Flag to indicate that a Tor circuit is thought to have been established. - bool _enabled = false; - - /// Getter for the enabled flag. - bool get enabled => _enabled; - - TorService._(); + /// Current status. Same as that fired on the event bus + TorConnectionStatus get status => _status; + TorConnectionStatus _status = TorConnectionStatus.disconnected; /// Singleton instance of the TorService. /// /// Use this to access the TorService and its properties. static final sharedInstance = TorService._(); + // private constructor for singleton + TorService._(); + /// Getter for the proxyInfo. + /// + /// Returns null if disabled on the stack wallet level. ({ InternetAddress host, int port, - }) get proxyInfo => ( + }) getProxyInfo() { + if (status == TorConnectionStatus.connected) { + return ( host: InternetAddress.loopbackIPv4, port: _tor!.port, ); + } else { + throw Exception("Tor proxy info fetched while not connected!"); + } + } /// Initialize the tor ffi lib instance if it hasn't already been set. Nothing /// changes if _tor is already been set. - void init({Tor? mockableOverride}) { + void init({ + required String torDataDirPath, + Tor? mockableOverride, + }) { _tor ??= mockableOverride ?? Tor.instance; + _torDataDirPath ??= torDataDirPath; } /// Start the Tor service. @@ -47,46 +59,25 @@ class TorService { /// /// Returns a Future that completes when the Tor service has started. Future start() async { - if (_tor == null) { + if (_tor == null || _torDataDirPath == null) { throw Exception("TorService.init has not been called!"); } - if (_enabled) { - // already started so just return - // could throw an exception here or something so the caller - // is explicitly made aware of this - // TODO restart tor after that's been added to the tor-ffi crate - // (probably better to have a restart function separately) - - // Fire a TorConnectionStatusChangedEvent on the event bus. - GlobalEventBus.instance.fire( - TorConnectionStatusChangedEvent( - TorConnectionStatus.connected, - "Tor connection status changed: connect ($_enabled)", - ), - ); - return; - } - // Start the Tor service. try { - GlobalEventBus.instance.fire( - TorConnectionStatusChangedEvent( - TorConnectionStatus.connecting, - "Tor connection status changed: connecting", - ), + _updateStatusAndFireEvent( + status: TorConnectionStatus.connecting, + message: "TorService.start call in progress", ); - await _tor!.start(); + + await _tor!.start(torDataDirPath: _torDataDirPath!); + // no exception or error so we can (probably?) assume tor // has started successfully - _enabled = true; - // Fire a TorConnectionStatusChangedEvent on the event bus. - GlobalEventBus.instance.fire( - TorConnectionStatusChangedEvent( - TorConnectionStatus.connected, - "Tor connection status changed: connect ($_enabled)", - ), + _updateStatusAndFireEvent( + status: TorConnectionStatus.connected, + message: "TorService.start call success", ); } catch (e, s) { Logging.instance.log( @@ -96,47 +87,41 @@ class TorService { // _enabled should already be false // Fire a TorConnectionStatusChangedEvent on the event bus. - GlobalEventBus.instance.fire( - TorConnectionStatusChangedEvent( - TorConnectionStatus.disconnected, - "Tor connection status changed: $_enabled (failed)", - ), + _updateStatusAndFireEvent( + status: TorConnectionStatus.disconnected, + message: "TorService.start call failed", ); rethrow; } } - Future stop() async { + /// disable tor + Future disable() async { if (_tor == null) { throw Exception("TorService.init has not been called!"); } - if (!_enabled) { - // already stopped so just return - // could throw an exception here or something so the caller - // is explicitly made aware of this - // TODO make sure to kill + // no need to update status and fire event if status won't change + if (_status == TorConnectionStatus.disconnected) { return; } - // Stop the Tor service. - try { - _tor!.disable(); - // no exception or error so we can (probably?) assume tor - // has started successfully - _enabled = false; - GlobalEventBus.instance.fire( - TorConnectionStatusChangedEvent( - TorConnectionStatus.disconnected, - "Tor connection status changed: $_enabled (disabled)", - ), - ); - } catch (e, s) { - Logging.instance.log( - "TorService.stop failed: $e\n$s", - level: LogLevel.Warning, - ); - rethrow; - } + _updateStatusAndFireEvent( + status: TorConnectionStatus.disconnected, + message: "TorService.disable call success", + ); + } + + void _updateStatusAndFireEvent({ + required TorConnectionStatus status, + required String message, + }) { + _status = status; + GlobalEventBus.instance.fire( + TorConnectionStatusChangedEvent( + _status, + message, + ), + ); } } diff --git a/lib/themes/theme_service.dart b/lib/themes/theme_service.dart index 62165d646..01134da66 100644 --- a/lib/themes/theme_service.dart +++ b/lib/themes/theme_service.dart @@ -213,8 +213,9 @@ class ThemeService { try { final response = await client.get( url: Uri.parse("$baseServerUrl/themes"), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); final jsonList = jsonDecode(response.body) as List; @@ -240,8 +241,9 @@ class ThemeService { try { final response = await client.get( url: Uri.parse("$baseServerUrl/theme/${themeMetaData.id}"), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); final bytes = Uint8List.fromList(response.bodyBytes); diff --git a/lib/utilities/assets.dart b/lib/utilities/assets.dart index 9880e12c5..f6a454b7f 100644 --- a/lib/utilities/assets.dart +++ b/lib/utilities/assets.dart @@ -258,4 +258,5 @@ class _ANIMATIONS { String get iconSend => "assets/lottie/icon_send.json"; String get loaderAndCheckmark => "assets/lottie/loader_and_checkmark.json"; String get arrowRotate => "assets/lottie/arrow_rotate.json"; + String get onionTor => "assets/lottie/onion_animation.json"; } diff --git a/lib/utilities/paynym_is_api.dart b/lib/utilities/paynym_is_api.dart index 860848cac..1393af4f1 100644 --- a/lib/utilities/paynym_is_api.dart +++ b/lib/utilities/paynym_is_api.dart @@ -52,8 +52,9 @@ class PaynymIsApi { url: uri, headers: headers, body: jsonEncode(body), - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ); debugPrint("Paynym request uri: $uri"); diff --git a/lib/utilities/test_epic_box_connection.dart b/lib/utilities/test_epic_box_connection.dart index ed2fd4828..600438451 100644 --- a/lib/utilities/test_epic_box_connection.dart +++ b/lib/utilities/test_epic_box_connection.dart @@ -24,7 +24,7 @@ Future _testEpicBoxNodeConnection(Uri uri) async { url: uri, headers: {'Content-Type': 'application/json'}, proxyInfo: Prefs.instance.useTor - ? TorService.sharedInstance.proxyInfo + ? TorService.sharedInstance.getProxyInfo() : null, ) .timeout(const Duration(milliseconds: 2000), diff --git a/lib/utilities/test_stellar_node_connection.dart b/lib/utilities/test_stellar_node_connection.dart index 32f756025..73d20a8aa 100644 --- a/lib/utilities/test_stellar_node_connection.dart +++ b/lib/utilities/test_stellar_node_connection.dart @@ -13,8 +13,9 @@ Future testStellarNodeConnection(String host, int port) async { .get( url: uri, headers: {'Content-Type': 'application/json'}, - proxyInfo: - Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null, + proxyInfo: Prefs.instance.useTor + ? TorService.sharedInstance.getProxyInfo() + : null, ) .timeout(const Duration(milliseconds: 2000), onTimeout: () async => http.Response(utf8.encode('Error'), 408)); diff --git a/lib/widgets/desktop/desktop_tor_status_button.dart b/lib/widgets/desktop/desktop_tor_status_button.dart index 42677aa0f..8b7e96ec2 100644 --- a/lib/widgets/desktop/desktop_tor_status_button.dart +++ b/lib/widgets/desktop/desktop_tor_status_button.dart @@ -81,9 +81,7 @@ class _DesktopTorStatusButtonState extends ConsumerState eventBus = GlobalEventBus.instance; // Initialize the TorConnectionStatus. - _torConnectionStatus = ref.read(pTorService).enabled - ? TorConnectionStatus.connected - : TorConnectionStatus.disconnected; + _torConnectionStatus = ref.read(pTorService).status; // Subscribe to the TorConnectionStatusChangedEvent. _torConnectionStatusSubscription = @@ -93,25 +91,6 @@ class _DesktopTorStatusButtonState extends ConsumerState setState(() { _torConnectionStatus = event.newStatus; }); - - // TODO implement spinner or animations and control from here - // switch (event.newStatus) { - // case TorConnectionStatus.disconnected: - // // if (_spinController.hasLoadedAnimation) { - // // _spinController.stop?.call(); - // // } - // break; - // case TorConnectionStatus.connecting: - // // if (_spinController.hasLoadedAnimation) { - // // _spinController.repeat?.call(); - // // } - // break; - // case TorConnectionStatus.connected: - // // if (_spinController.hasLoadedAnimation) { - // // _spinController.stop?.call(); - // // } - // break; - // } }, ); diff --git a/lib/widgets/small_tor_icon.dart b/lib/widgets/small_tor_icon.dart index c032fbdae..711a77ba5 100644 --- a/lib/widgets/small_tor_icon.dart +++ b/lib/widgets/small_tor_icon.dart @@ -37,9 +37,7 @@ class _SmallTorIconState extends ConsumerState { @override void initState() { - _status = ref.read(pTorService).enabled - ? TorConnectionStatus.connected - : TorConnectionStatus.disconnected; + _status = ref.read(pTorService).status; super.initState(); } diff --git a/pubspec.lock b/pubspec.lock index 255b669d3..934394e2a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1655,9 +1655,11 @@ packages: tor_ffi_plugin: dependency: "direct main" description: - path: "crypto_plugins/tor" - relative: true - source: path + path: "." + ref: "8a26a160bdc4dcac2ba5a0350a151a345d1dead9" + resolved-ref: "8a26a160bdc4dcac2ba5a0350a151a345d1dead9" + url: "https://github.com/cypherstack/tor.git" + source: git version: "0.0.1" tuple: dependency: "direct main" diff --git a/pubspec.yaml b/pubspec.yaml index 0b6346054..5c3c50059 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,7 +58,9 @@ dependencies: ref: 081ca1863c2feba00c35bb5b297902f12f499941 tor_ffi_plugin: - path: ./crypto_plugins/tor + git: + url: https://github.com/cypherstack/tor.git + ref: 8a26a160bdc4dcac2ba5a0350a151a345d1dead9 # Utility plugins http: ^0.13.0 @@ -377,6 +379,7 @@ flutter: - assets/lottie/icon_send.json - assets/lottie/loader_and_checkmark.json - assets/lottie/arrow_rotate.json + - assets/lottie/onion_animation.json # default themes_testing - assets/default_themes/ diff --git a/test/electrumx_test.dart b/test/electrumx_test.dart index 0d8bb93d1..cbf978f9c 100644 --- a/test/electrumx_test.dart +++ b/test/electrumx_test.dart @@ -5,6 +5,7 @@ import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart'; import 'package:stackwallet/electrumx_rpc/rpc.dart'; +import 'package:stackwallet/services/event_bus/events/global/tor_connection_status_changed_event.dart'; import 'package:stackwallet/services/tor_service.dart'; import 'package:stackwallet/utilities/prefs.dart'; @@ -1528,7 +1529,8 @@ void main() { .thenAnswer((_) => false); // Or true, shouldn't matter. when(mockPrefs.wifiOnly).thenAnswer((_) => false); final mockTorService = MockTorService(); - when(mockTorService.enabled).thenAnswer((_) => false); + when(mockTorService.status) + .thenAnswer((_) => TorConnectionStatus.disconnected); final client = ElectrumX( host: "some server", @@ -1551,7 +1553,7 @@ void main() { verify(mockPrefs.useTor).called(1); verifyNever(mockPrefs.torKillSwitch); verifyNoMoreInteractions(mockPrefs); - verifyNever(mockTorService.enabled); + verifyNever(mockTorService.status); verifyNoMoreInteractions(mockTorService); }); @@ -1575,8 +1577,9 @@ void main() { when(mockPrefs.wifiOnly).thenAnswer((_) => false); final mockTorService = MockTorService(); - when(mockTorService.enabled).thenAnswer((_) => false); - when(mockTorService.proxyInfo).thenAnswer((_) => ( + when(mockTorService.status) + .thenAnswer((_) => TorConnectionStatus.disconnected); + when(mockTorService.getProxyInfo()).thenAnswer((_) => ( host: InternetAddress('1.2.3.4'), port: -1 )); // Port is set to -1 until Tor is enabled. @@ -1601,8 +1604,8 @@ void main() { verify(mockPrefs.useTor).called(1); verify(mockPrefs.torKillSwitch).called(1); verifyNoMoreInteractions(mockPrefs); - verify(mockTorService.enabled).called(1); - verifyNever(mockTorService.proxyInfo); + verify(mockTorService.status).called(1); + verifyNever(mockTorService.getProxyInfo()); verifyNoMoreInteractions(mockTorService); }); @@ -1628,8 +1631,9 @@ void main() { when(mockPrefs.wifiOnly).thenAnswer((_) => false); final mockTorService = MockTorService(); - when(mockTorService.enabled).thenAnswer((_) => true); - when(mockTorService.proxyInfo) + when(mockTorService.status) + .thenAnswer((_) => TorConnectionStatus.connected); + when(mockTorService.getProxyInfo()) .thenAnswer((_) => (host: InternetAddress('1.2.3.4'), port: 42)); final client = ElectrumX( @@ -1653,8 +1657,8 @@ void main() { verify(mockPrefs.useTor).called(1); verifyNever(mockPrefs.torKillSwitch); verifyNoMoreInteractions(mockPrefs); - verify(mockTorService.enabled).called(1); - verify(mockTorService.proxyInfo).called(1); + verify(mockTorService.status).called(1); + verify(mockTorService.getProxyInfo()).called(1); verifyNoMoreInteractions(mockTorService); }); @@ -1685,7 +1689,8 @@ void main() { when(mockPrefs.torKillSwitch).thenAnswer((_) => true); when(mockPrefs.wifiOnly).thenAnswer((_) => false); final mockTorService = MockTorService(); - when(mockTorService.enabled).thenAnswer((_) => false); + when(mockTorService.status) + .thenAnswer((_) => TorConnectionStatus.disconnected); final client = ElectrumX( host: "some server", @@ -1712,7 +1717,7 @@ void main() { verify(mockPrefs.useTor).called(1); verify(mockPrefs.torKillSwitch).called(1); verifyNoMoreInteractions(mockPrefs); - verify(mockTorService.enabled).called(1); + verify(mockTorService.status).called(1); verifyNoMoreInteractions(mockTorService); }); @@ -1740,7 +1745,8 @@ void main() { when(mockPrefs.torKillSwitch).thenAnswer((_) => false); when(mockPrefs.wifiOnly).thenAnswer((_) => false); final mockTorService = MockTorService(); - when(mockTorService.enabled).thenAnswer((_) => false); + when(mockTorService.status) + .thenAnswer((_) => TorConnectionStatus.disconnected); final client = ElectrumX( host: "some server", @@ -1763,7 +1769,7 @@ void main() { verify(mockPrefs.useTor).called(1); verify(mockPrefs.torKillSwitch).called(1); verifyNoMoreInteractions(mockPrefs); - verify(mockTorService.enabled).called(1); + verify(mockTorService.status).called(1); verifyNoMoreInteractions(mockTorService); }); }); diff --git a/test/electrumx_test.mocks.dart b/test/electrumx_test.mocks.dart index d77c3e76d..557b983a6 100644 --- a/test/electrumx_test.mocks.dart +++ b/test/electrumx_test.mocks.dart @@ -9,13 +9,15 @@ import 'dart:ui' as _i10; import 'package:mockito/mockito.dart' as _i1; import 'package:stackwallet/electrumx_rpc/rpc.dart' as _i2; +import 'package:stackwallet/services/event_bus/events/global/tor_connection_status_changed_event.dart' + as _i12; import 'package:stackwallet/services/tor_service.dart' as _i11; import 'package:stackwallet/utilities/amount/amount_unit.dart' as _i8; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i7; import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i9; import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i6; import 'package:stackwallet/utilities/prefs.dart' as _i5; -import 'package:tor_ffi_plugin/tor_ffi_plugin.dart' as _i12; +import 'package:tor_ffi_plugin/tor_ffi_plugin.dart' as _i13; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -659,27 +661,40 @@ class MockTorService extends _i1.Mock implements _i11.TorService { } @override - bool get enabled => (super.noSuchMethod( - Invocation.getter(#enabled), - returnValue: false, - ) as bool); + _i12.TorConnectionStatus get status => (super.noSuchMethod( + Invocation.getter(#status), + returnValue: _i12.TorConnectionStatus.disconnected, + ) as _i12.TorConnectionStatus); @override - ({_i3.InternetAddress host, int port}) get proxyInfo => (super.noSuchMethod( - Invocation.getter(#proxyInfo), + ({_i3.InternetAddress host, int port}) getProxyInfo() => (super.noSuchMethod( + Invocation.method( + #getProxyInfo, + [], + ), returnValue: ( host: _FakeInternetAddress_2( this, - Invocation.getter(#proxyInfo), + Invocation.method( + #getProxyInfo, + [], + ), ), port: 0 ), ) as ({_i3.InternetAddress host, int port})); @override - void init({_i12.Tor? mockableOverride}) => super.noSuchMethod( + void init({ + required String? torDataDirPath, + _i13.Tor? mockableOverride, + }) => + super.noSuchMethod( Invocation.method( #init, [], - {#mockableOverride: mockableOverride}, + { + #torDataDirPath: torDataDirPath, + #mockableOverride: mockableOverride, + }, ), returnValueForMissingStub: null, ); @@ -693,9 +708,9 @@ class MockTorService extends _i1.Mock implements _i11.TorService { returnValueForMissingStub: _i4.Future.value(), ) as _i4.Future); @override - _i4.Future stop() => (super.noSuchMethod( + _i4.Future disable() => (super.noSuchMethod( Invocation.method( - #stop, + #disable, [], ), returnValue: _i4.Future.value(), diff --git a/test/widget_tests/node_options_sheet_test.mocks.dart b/test/widget_tests/node_options_sheet_test.mocks.dart index 203e196a0..42528b822 100644 --- a/test/widget_tests/node_options_sheet_test.mocks.dart +++ b/test/widget_tests/node_options_sheet_test.mocks.dart @@ -12,6 +12,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart' as _i5; import 'package:mockito/mockito.dart' as _i1; import 'package:stackwallet/models/node_model.dart' as _i18; import 'package:stackwallet/services/coins/manager.dart' as _i6; +import 'package:stackwallet/services/event_bus/events/global/tor_connection_status_changed_event.dart' + as _i20; import 'package:stackwallet/services/node_service.dart' as _i3; import 'package:stackwallet/services/tor_service.dart' as _i19; import 'package:stackwallet/services/wallets.dart' as _i9; @@ -23,7 +25,7 @@ import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i15; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart' as _i7; import 'package:stackwallet/utilities/prefs.dart' as _i13; -import 'package:tor_ffi_plugin/tor_ffi_plugin.dart' as _i20; +import 'package:tor_ffi_plugin/tor_ffi_plugin.dart' as _i21; import 'package:tuple/tuple.dart' as _i11; // ignore_for_file: type=lint @@ -1025,27 +1027,40 @@ class MockTorService extends _i1.Mock implements _i19.TorService { } @override - bool get enabled => (super.noSuchMethod( - Invocation.getter(#enabled), - returnValue: false, - ) as bool); + _i20.TorConnectionStatus get status => (super.noSuchMethod( + Invocation.getter(#status), + returnValue: _i20.TorConnectionStatus.disconnected, + ) as _i20.TorConnectionStatus); @override - ({_i8.InternetAddress host, int port}) get proxyInfo => (super.noSuchMethod( - Invocation.getter(#proxyInfo), + ({_i8.InternetAddress host, int port}) getProxyInfo() => (super.noSuchMethod( + Invocation.method( + #getProxyInfo, + [], + ), returnValue: ( host: _FakeInternetAddress_5( this, - Invocation.getter(#proxyInfo), + Invocation.method( + #getProxyInfo, + [], + ), ), port: 0 ), ) as ({_i8.InternetAddress host, int port})); @override - void init({_i20.Tor? mockableOverride}) => super.noSuchMethod( + void init({ + required String? torDataDirPath, + _i21.Tor? mockableOverride, + }) => + super.noSuchMethod( Invocation.method( #init, [], - {#mockableOverride: mockableOverride}, + { + #torDataDirPath: torDataDirPath, + #mockableOverride: mockableOverride, + }, ), returnValueForMissingStub: null, ); @@ -1059,9 +1074,9 @@ class MockTorService extends _i1.Mock implements _i19.TorService { returnValueForMissingStub: _i12.Future.value(), ) as _i12.Future); @override - _i12.Future stop() => (super.noSuchMethod( + _i12.Future disable() => (super.noSuchMethod( Invocation.method( - #stop, + #disable, [], ), returnValue: _i12.Future.value(),