diff --git a/.github/workflows/flutter_build.yml b/.github/workflows/flutter_build.yml
index dd19244aa..d1d1078a7 100644
--- a/.github/workflows/flutter_build.yml
+++ b/.github/workflows/flutter_build.yml
@@ -27,8 +27,7 @@ jobs:
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
- flutter-version: '3.16.5'
- - run: "flutter upgrade"
+ flutter-version: '3.19.6'
- run: "flutter --version"
- run: "flutter pub get"
- run: "flutter build ios -t 'lib/mains/main_netknights.dart' --debug --flavor netknights --no-codesign"
@@ -48,14 +47,13 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
- distribution: 'zulu'
- java-version: '17.0.7'
+ distribution: 'oracle'
+ java-version: '17'
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
- flutter-version: '3.19.0'
- - run: "flutter upgrade"
+ flutter-version: '3.19.6'
+ - run: 'flutter clean'
- run: "flutter --version"
- run: "flutter pub get"
- - run: 'flutter clean'
- - run: "flutter build apk -t 'lib/mains/main_netknights.dart' --debug --flavor netknights"
\ No newline at end of file
+ - run: "flutter build apk -t 'lib/mains/main_netknights.dart' --debug --flavor netknights"
diff --git a/.gitignore b/.gitignore
index c7c2122a5..2fae39ee8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -890,3 +890,4 @@ DerivedData/
.flutter-plugins-dependencies
lib/l10n/untranslated.txt
*.jks
+ios/Flutter/flutter_export_environment.sh
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index b7a7b150b..e784db90e 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -9,8 +9,6 @@
-
-
diff --git a/android/app/src/netknights/res/drawable-hdpi/hw_background.png b/android/app/src/netknights/res/drawable-hdpi/hw_background.png
new file mode 100644
index 000000000..ac9ba78be
Binary files /dev/null and b/android/app/src/netknights/res/drawable-hdpi/hw_background.png differ
diff --git a/android/app/src/netknights/res/drawable-mdpi/hw_background.png b/android/app/src/netknights/res/drawable-mdpi/hw_background.png
new file mode 100644
index 000000000..ac9ba78be
Binary files /dev/null and b/android/app/src/netknights/res/drawable-mdpi/hw_background.png differ
diff --git a/android/app/src/netknights/res/drawable-xhdpi/hw_background.png b/android/app/src/netknights/res/drawable-xhdpi/hw_background.png
new file mode 100644
index 000000000..ac9ba78be
Binary files /dev/null and b/android/app/src/netknights/res/drawable-xhdpi/hw_background.png differ
diff --git a/android/app/src/netknights/res/drawable-xxhdpi/hw_background.png b/android/app/src/netknights/res/drawable-xxhdpi/hw_background.png
new file mode 100644
index 000000000..ac9ba78be
Binary files /dev/null and b/android/app/src/netknights/res/drawable-xxhdpi/hw_background.png differ
diff --git a/android/app/src/netknights/res/drawable-xxxhdpi/hw_background.png b/android/app/src/netknights/res/drawable-xxxhdpi/hw_background.png
new file mode 100644
index 000000000..ac9ba78be
Binary files /dev/null and b/android/app/src/netknights/res/drawable-xxxhdpi/hw_background.png differ
diff --git a/android/app/src/netknights/res/drawable/app_icon.png b/android/app/src/netknights/res/drawable/app_icon.png
deleted file mode 100644
index f1142776d..000000000
Binary files a/android/app/src/netknights/res/drawable/app_icon.png and /dev/null differ
diff --git a/android/app/src/netknights/res/drawable/hw_background.png b/android/app/src/netknights/res/drawable/hw_background.png
new file mode 100644
index 000000000..ac9ba78be
Binary files /dev/null and b/android/app/src/netknights/res/drawable/hw_background.png differ
diff --git a/coverage/lcov.info b/coverage/lcov.info
index 29fa84cc5..f7f21aaf6 100644
--- a/coverage/lcov.info
+++ b/coverage/lcov.info
@@ -1,600 +1,509 @@
-SF:lib\model\states\token_folder_state.dart
-DA:11,19
-DA:13,2
-DA:14,4
-DA:15,6
-DA:16,2
-DA:21,2
-DA:22,4
-DA:23,4
-DA:24,10
-DA:25,4
-DA:26,2
-DA:29,2
-DA:32,2
-DA:33,4
-DA:34,10
-DA:35,2
+SF:lib\model\enums\introduction.dart
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
DA:38,0
DA:39,0
DA:40,0
DA:41,0
+DA:42,0
+DA:43,0
DA:44,0
+DA:45,0
DA:46,0
+DA:47,0
DA:48,0
DA:49,0
+DA:50,0
DA:51,0
DA:52,0
-DA:54,10
-LF:27
-LH:17
-end_of_record
-SF:lib\model\token_folder.dart
-DA:18,6
-DA:26,1
-DA:34,1
-DA:35,1
-DA:36,1
-DA:37,1
-DA:38,1
-DA:39,0
-DA:43,1
-DA:44,4
-DA:46,0
-DA:47,0
-DA:49,0
-DA:50,0
-DA:52,1
-DA:53,1
-DA:54,2
+DA:53,0
+DA:54,0
DA:57,0
-LF:18
-LH:12
+DA:58,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:67,0
+LF:32
+LH:0
end_of_record
-SF:lib\model\mixins\sortable_mixin.dart
-DA:6,0
-DA:7,0
-DA:8,0
+SF:lib\model\states\introduction_state.dart
DA:11,0
DA:13,0
-LF:5
-LH:0
-end_of_record
-SF:lib\model\token_folder.g.dart
-DA:9,2
-DA:10,1
-DA:11,1
-DA:12,1
-DA:13,1
-DA:14,1
-DA:17,0
+DA:14,0
+DA:16,36
DA:18,0
DA:19,0
-DA:20,0
-DA:21,0
-DA:22,0
-DA:23,0
-LF:13
-LH:6
-end_of_record
-SF:lib\model\states\token_state.dart
-DA:11,4
-DA:12,4
-DA:14,2
-DA:16,2
-DA:17,10
-DA:20,1
-DA:21,2
-DA:22,1
+DA:21,1
+DA:22,2
DA:23,1
-DA:26,1
-DA:27,2
-DA:28,1
+DA:24,1
+DA:27,1
+DA:28,2
DA:29,1
-DA:32,2
-DA:33,4
-DA:34,10
-DA:35,2
-DA:38,1
-DA:39,2
-DA:40,7
-DA:41,1
-DA:45,2
-DA:46,4
-DA:47,10
-DA:48,4
-DA:49,2
-DA:51,2
-DA:53,2
-DA:58,2
-DA:59,4
-DA:60,4
-DA:61,10
-DA:62,4
-DA:63,2
-DA:66,2
-DA:68,2
-DA:71,0
-DA:72,0
-DA:73,0
-LF:39
-LH:36
-end_of_record
-SF:lib\model\tokens\token.dart
-DA:27,0
-DA:28,0
-DA:29,0
-DA:30,0
-DA:31,0
-DA:32,0
+DA:30,1
DA:33,0
-DA:35,1
-DA:36,1
-DA:37,5
-DA:38,0
-DA:39,0
-DA:40,0
-DA:41,0
-DA:44,6
-DA:70,1
-DA:72,4
-DA:75,0
-DA:76,0
-DA:78,1
-DA:80,10
-LF:21
-LH:8
+DA:35,0
+DA:36,0
+LF:17
+LH:9
end_of_record
-SF:lib\model\states\settings_state.dart
+SF:lib\model\states\introduction_state.g.dart
+DA:9,0
+DA:10,0
DA:11,0
DA:12,0
DA:13,0
-DA:14,0
-DA:15,0
-DA:16,0
DA:17,0
+DA:18,0
DA:19,0
DA:20,0
-DA:28,0
-DA:30,0
-DA:31,0
-DA:35,1
-DA:44,0
-DA:45,0
-DA:46,0
-DA:47,0
-DA:48,0
-DA:49,0
-DA:50,0
-DA:51,0
+DA:21,0
+LF:10
+LH:0
+end_of_record
+SF:lib\model\push_request.dart
+DA:28,1
+DA:41,1
DA:53,1
+DA:54,1
+DA:55,1
+DA:56,1
+DA:57,1
+DA:58,1
+DA:59,1
+DA:60,1
+DA:61,1
+DA:62,1
DA:63,1
-DA:64,1
-DA:65,1
-DA:66,1
DA:67,1
-DA:68,1
-DA:69,1
-DA:70,1
-DA:71,1
-DA:75,1
-DA:77,9
-DA:79,0
-DA:80,0
-DA:83,1
-DA:88,1
-DA:89,3
-DA:90,3
-DA:91,3
-DA:92,3
-DA:93,5
-DA:94,5
-DA:95,3
-DA:96,3
-DA:99,0
-DA:100,0
-DA:101,0
-LF:48
-LH:23
-end_of_record
-SF:lib\l10n\app_localizations.dart
-DA:68,0
-DA:72,0
-DA:73,0
-DA:852,16
-DA:854,0
-DA:856,0
-DA:859,0
-DA:860,0
-DA:862,0
-DA:866,0
-DA:870,0
-DA:871,0
-DA:872,0
-DA:873,0
-DA:874,0
-DA:875,0
-DA:876,0
-DA:877,0
-DA:880,0
-LF:19
-LH:1
-end_of_record
-SF:lib\l10n\app_localizations_cs.dart
-DA:5,0
-DA:7,0
-DA:10,0
-DA:13,0
-DA:16,0
-DA:19,0
-DA:22,0
-DA:25,0
-DA:28,0
-DA:31,0
-DA:34,0
-DA:37,0
-DA:40,0
-DA:43,0
-DA:46,0
-DA:49,0
-DA:52,0
-DA:55,0
-DA:58,0
-DA:61,0
-DA:64,0
-DA:67,0
+DA:68,7
DA:70,0
-DA:72,0
+DA:71,0
+DA:73,0
DA:75,0
+DA:76,0
+DA:77,0
DA:78,0
DA:81,0
DA:83,0
-DA:86,0
+DA:85,0
+DA:87,0
DA:89,0
+DA:91,0
DA:92,0
+DA:93,0
+DA:94,0
DA:95,0
+DA:96,0
+DA:97,0
DA:98,0
-DA:101,0
-DA:104,0
+DA:99,0
+DA:100,0
+DA:106,0
DA:107,0
+DA:108,0
DA:110,0
+DA:111,0
DA:113,0
+DA:114,0
+DA:115,0
DA:116,0
+DA:118,0
DA:119,0
+DA:121,0
DA:122,0
+DA:124,0
DA:125,0
+DA:127,0
DA:128,0
-DA:131,0
+DA:132,0
DA:133,0
+DA:134,0
+DA:135,0
DA:136,0
+DA:137,0
+DA:138,0
DA:139,0
-DA:141,0
-DA:144,0
+DA:142,0
+DA:143,0
DA:146,0
-DA:149,0
-DA:152,0
-DA:155,0
+DA:147,0
+DA:148,0
+DA:151,0
DA:158,0
-DA:161,0
-DA:164,0
-DA:167,0
-DA:170,0
-DA:173,0
-DA:176,0
-DA:179,0
-DA:182,0
-DA:185,0
-DA:188,0
-DA:191,0
-DA:194,0
-DA:197,0
-DA:200,0
-DA:203,0
-DA:206,0
-DA:209,0
-DA:212,0
-DA:215,0
-DA:218,0
-DA:221,0
-DA:224,0
-DA:227,0
-DA:229,0
-DA:232,0
-DA:235,0
-DA:238,0
-DA:241,0
-DA:244,0
-DA:247,0
-DA:250,0
-DA:253,0
-DA:256,0
-DA:259,0
-DA:262,0
-DA:265,0
-DA:268,0
-DA:271,0
-DA:274,0
-DA:277,0
-DA:280,0
-DA:283,0
-DA:286,0
-DA:289,0
-DA:292,0
-DA:295,0
-DA:298,0
-DA:301,0
-DA:304,0
-DA:307,0
-DA:310,0
-DA:313,0
-DA:316,0
-DA:319,0
-DA:322,0
-DA:325,0
-DA:328,0
-DA:331,0
-DA:334,0
-DA:337,0
-DA:340,0
-DA:343,0
-DA:346,0
-DA:349,0
-DA:352,0
-DA:355,0
-DA:358,0
-DA:361,0
-DA:364,0
-DA:367,0
-DA:370,0
-DA:372,0
-DA:375,0
-DA:377,0
-DA:380,0
-DA:383,0
-DA:386,0
-DA:389,0
-DA:392,0
-LF:133
-LH:0
+LF:69
+LH:15
end_of_record
-SF:lib\l10n\app_localizations_de.dart
-DA:5,0
-DA:7,0
+SF:lib\model\push_request.g.dart
+DA:9,0
DA:10,0
+DA:11,0
+DA:12,0
DA:13,0
+DA:14,0
+DA:15,0
DA:16,0
+DA:17,0
+DA:18,0
DA:19,0
DA:22,0
+DA:23,0
+DA:24,0
DA:25,0
+DA:26,0
+DA:27,0
DA:28,0
+DA:29,0
+DA:30,0
DA:31,0
-DA:34,0
+DA:32,0
+DA:33,0
+LF:23
+LH:0
+end_of_record
+SF:lib\model\states\push_request_state.dart
+DA:13,35
+DA:15,3
+DA:16,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:24,2
+DA:25,3
+DA:26,2
+DA:29,1
+DA:30,2
+DA:31,2
+DA:32,1
+DA:33,0
+DA:35,0
+DA:36,0
DA:37,0
-DA:40,0
-DA:43,0
-DA:46,0
-DA:49,0
-DA:52,0
-DA:55,0
-DA:58,0
-DA:61,0
-DA:64,0
+DA:40,2
+DA:41,1
+DA:42,1
+DA:43,1
+DA:47,1
+DA:48,2
+DA:49,5
+DA:50,2
+DA:53,1
+DA:54,2
+DA:57,7
+DA:59,1
+DA:63,7
+DA:66,0
DA:67,0
+DA:69,0
DA:70,0
-DA:72,0
-DA:75,0
+DA:77,0
DA:78,0
-DA:81,0
+DA:79,0
+DA:82,0
DA:83,0
-DA:86,0
-DA:89,0
-DA:92,0
-DA:95,0
-DA:98,0
-DA:101,0
-DA:104,0
-DA:107,0
-DA:110,0
-DA:113,0
-DA:116,0
-DA:119,0
-DA:122,0
-DA:125,0
-DA:128,0
-DA:131,0
-DA:133,0
-DA:136,0
-DA:139,0
-DA:141,0
-DA:144,0
-DA:146,0
-DA:149,0
-DA:152,0
-DA:155,0
-DA:158,0
-DA:161,0
-DA:164,0
-DA:167,0
-DA:170,0
-DA:173,0
-DA:176,0
-DA:179,0
-DA:182,0
-DA:185,0
-DA:188,0
-DA:191,0
-DA:194,0
-DA:197,0
-DA:200,0
-DA:203,0
-DA:206,0
-DA:209,0
-DA:212,0
-DA:215,0
-DA:218,0
-DA:221,0
-DA:224,0
-DA:227,0
-DA:229,0
-DA:232,0
-DA:235,0
-DA:238,0
-DA:241,0
-DA:244,0
-DA:247,0
-DA:250,0
-DA:253,0
-DA:256,0
-DA:259,0
-DA:262,0
-DA:265,0
-DA:268,0
-DA:271,0
-DA:274,0
-DA:277,0
-DA:280,0
-DA:283,0
-DA:286,0
-DA:289,0
-DA:292,0
-DA:295,0
-DA:298,0
-DA:301,0
-DA:304,0
-DA:307,0
-DA:310,0
-DA:313,0
-DA:316,0
-DA:319,0
-DA:322,0
-DA:325,0
-DA:328,0
-DA:331,0
-DA:334,0
-DA:337,0
-DA:340,0
-DA:343,0
-DA:346,0
-DA:349,0
-DA:352,0
-DA:355,0
-DA:358,0
-DA:361,0
-DA:364,0
-DA:367,0
-DA:370,0
-DA:372,0
-DA:375,0
-DA:377,0
-DA:380,0
-DA:383,0
-DA:386,0
-DA:389,0
-DA:392,0
-LF:133
-LH:0
+DA:84,0
+LF:40
+LH:22
end_of_record
-SF:lib\l10n\app_localizations_en.dart
-DA:5,0
-DA:7,0
+SF:lib\model\states\push_request_state.g.dart
+DA:9,0
DA:10,0
+DA:11,0
+DA:12,0
DA:13,0
-DA:16,0
-DA:19,0
-DA:22,0
-DA:25,0
-DA:28,0
+DA:14,0
+DA:15,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:21,0
+LF:11
+LH:0
+end_of_record
+SF:lib\model\states\settings_state.dart
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:20,0
+DA:21,0
+DA:22,2
+DA:23,4
DA:31,0
+DA:33,0
DA:34,0
-DA:37,0
-DA:40,0
-DA:43,0
-DA:46,0
-DA:49,0
+DA:40,2
+DA:51,0
DA:52,0
+DA:53,0
+DA:54,0
DA:55,0
+DA:56,0
+DA:57,0
DA:58,0
-DA:61,0
-DA:64,0
-DA:67,0
-DA:70,0
+DA:59,2
+DA:60,2
+DA:62,2
+DA:74,2
+DA:75,1
+DA:76,1
+DA:77,1
+DA:78,1
+DA:79,1
+DA:80,1
+DA:81,1
+DA:82,1
+DA:83,2
+DA:84,2
+DA:88,1
+DA:89,5
+DA:90,4
+DA:91,1
+DA:93,1
+DA:94,3
+DA:97,1
+DA:102,1
+DA:103,3
+DA:104,3
+DA:105,3
+DA:106,3
+DA:107,5
+DA:108,5
+DA:109,3
+DA:110,3
+DA:111,3
+DA:114,1
+DA:115,1
+DA:116,4
+LF:57
+LH:37
+end_of_record
+SF:lib\model\token_folder.dart
+DA:18,6
+DA:26,1
+DA:34,1
+DA:35,1
+DA:36,1
+DA:37,1
+DA:38,1
+DA:39,0
+DA:43,1
+DA:44,4
+DA:46,0
+DA:47,0
+DA:49,0
+DA:50,0
+DA:52,1
+DA:53,1
+DA:54,2
+DA:57,0
+LF:18
+LH:12
+end_of_record
+SF:lib\model\mixins\sortable_mixin.dart
+DA:6,0
+DA:7,0
+DA:8,0
+DA:11,0
+DA:13,0
+LF:5
+LH:0
+end_of_record
+SF:lib\model\token_folder.g.dart
+DA:9,2
+DA:10,1
+DA:11,1
+DA:12,1
+DA:13,1
+DA:14,1
+DA:17,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+LF:13
+LH:6
+end_of_record
+SF:lib\model\tokens\token.dart
+DA:16,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:43,1
+DA:46,1
+DA:47,1
+DA:48,2
+DA:49,2
+DA:50,0
+DA:51,0
+DA:52,0
+DA:55,6
+DA:69,6
+DA:73,0
+DA:74,0
+DA:77,0
+DA:78,0
+DA:95,1
+DA:97,4
+DA:100,0
+DA:101,0
+DA:103,0
+DA:105,0
+DA:106,0
+DA:107,0
+DA:108,0
+DA:109,0
+DA:110,0
+DA:111,0
+DA:112,0
+DA:113,0
+DA:114,0
+DA:115,0
+LF:39
+LH:9
+end_of_record
+SF:lib\l10n\app_localizations.dart
+DA:68,0
+DA:72,0
+DA:73,0
+DA:1650,17
+DA:1652,0
+DA:1654,0
+DA:1657,0
+DA:1658,0
+DA:1660,0
+DA:1664,0
+DA:1668,0
+DA:1669,0
+DA:1670,0
+DA:1671,0
+DA:1672,0
+DA:1673,0
+DA:1674,0
+DA:1675,0
+DA:1678,0
+LF:19
+LH:1
+end_of_record
+SF:lib\l10n\app_localizations_cs.dart
+DA:7,0
+DA:9,0
+DA:12,0
+DA:15,0
+DA:18,0
+DA:21,0
+DA:24,0
+DA:27,0
+DA:30,0
+DA:33,0
+DA:36,0
+DA:39,0
+DA:42,0
+DA:45,0
+DA:48,0
+DA:51,0
+DA:54,0
+DA:57,0
+DA:60,0
+DA:63,0
+DA:66,0
+DA:69,0
DA:72,0
DA:75,0
DA:78,0
DA:81,0
-DA:83,0
-DA:86,0
-DA:89,0
-DA:92,0
-DA:95,0
-DA:98,0
-DA:101,0
-DA:104,0
+DA:84,0
+DA:87,0
+DA:90,0
+DA:93,0
+DA:96,0
+DA:99,0
+DA:102,0
+DA:105,0
DA:107,0
DA:110,0
DA:113,0
DA:116,0
DA:119,0
DA:122,0
-DA:125,0
-DA:128,0
-DA:131,0
+DA:124,0
+DA:127,0
+DA:130,0
DA:133,0
DA:136,0
DA:139,0
-DA:141,0
-DA:144,0
-DA:146,0
-DA:149,0
-DA:152,0
-DA:155,0
-DA:158,0
-DA:161,0
-DA:164,0
-DA:167,0
-DA:170,0
-DA:173,0
-DA:176,0
-DA:179,0
+DA:142,0
+DA:145,0
+DA:148,0
+DA:151,0
+DA:154,0
+DA:157,0
+DA:160,0
+DA:163,0
+DA:166,0
+DA:169,0
+DA:172,0
+DA:175,0
+DA:177,0
+DA:180,0
DA:182,0
DA:185,0
DA:188,0
-DA:191,0
-DA:194,0
-DA:197,0
-DA:200,0
-DA:203,0
-DA:206,0
-DA:209,0
+DA:190,0
+DA:193,0
+DA:195,0
+DA:198,0
+DA:201,0
+DA:204,0
+DA:207,0
+DA:210,0
DA:212,0
DA:215,0
DA:218,0
DA:221,0
DA:224,0
DA:227,0
-DA:229,0
-DA:232,0
-DA:235,0
-DA:238,0
-DA:241,0
-DA:244,0
-DA:247,0
-DA:250,0
-DA:253,0
-DA:256,0
-DA:259,0
-DA:262,0
-DA:265,0
-DA:268,0
-DA:271,0
-DA:274,0
-DA:277,0
-DA:280,0
-DA:283,0
-DA:286,0
-DA:289,0
-DA:292,0
-DA:295,0
+DA:230,0
+DA:233,0
+DA:236,0
+DA:239,0
+DA:242,0
+DA:245,0
+DA:248,0
+DA:251,0
+DA:254,0
+DA:257,0
+DA:260,0
+DA:263,0
+DA:266,0
+DA:269,0
+DA:272,0
+DA:275,0
+DA:278,0
+DA:281,0
+DA:284,0
+DA:287,0
+DA:290,0
+DA:293,0
+DA:296,0
DA:298,0
DA:301,0
DA:304,0
@@ -620,118 +529,280 @@ DA:361,0
DA:364,0
DA:367,0
DA:370,0
-DA:372,0
-DA:375,0
-DA:377,0
-DA:380,0
-DA:383,0
-DA:386,0
-DA:389,0
-DA:392,0
-LF:133
+DA:373,0
+DA:376,0
+DA:379,0
+DA:382,0
+DA:385,0
+DA:388,0
+DA:391,0
+DA:394,0
+DA:397,0
+DA:400,0
+DA:403,0
+DA:406,0
+DA:409,0
+DA:412,0
+DA:415,0
+DA:418,0
+DA:421,0
+DA:424,0
+DA:427,0
+DA:430,0
+DA:433,0
+DA:436,0
+DA:439,0
+DA:442,0
+DA:445,0
+DA:448,0
+DA:450,0
+DA:453,0
+DA:456,0
+DA:458,0
+DA:461,0
+DA:464,0
+DA:467,0
+DA:470,0
+DA:473,0
+DA:476,0
+DA:479,0
+DA:482,0
+DA:485,0
+DA:488,0
+DA:491,0
+DA:494,0
+DA:497,0
+DA:500,0
+DA:503,0
+DA:506,0
+DA:509,0
+DA:512,0
+DA:515,0
+DA:518,0
+DA:521,0
+DA:524,0
+DA:527,0
+DA:530,0
+DA:533,0
+DA:536,0
+DA:539,0
+DA:542,0
+DA:545,0
+DA:548,0
+DA:550,0
+DA:553,0
+DA:556,0
+DA:559,0
+DA:562,0
+DA:565,0
+DA:568,0
+DA:571,0
+DA:574,0
+DA:577,0
+DA:580,0
+DA:583,0
+DA:586,0
+DA:589,0
+DA:592,0
+DA:594,0
+DA:597,0
+DA:599,0
+DA:602,0
+DA:604,0
+DA:607,0
+DA:609,0
+DA:612,0
+DA:614,0
+DA:616,0
+DA:617,0
+DA:621,0
+DA:624,0
+DA:626,0
+DA:628,0
+DA:629,0
+DA:633,0
+DA:636,0
+DA:638,0
+DA:640,0
+DA:645,0
+DA:648,0
+DA:650,0
+DA:652,0
+DA:653,0
+DA:657,0
+DA:660,0
+DA:663,0
+DA:666,0
+DA:669,0
+DA:672,0
+DA:675,0
+DA:678,0
+DA:681,0
+DA:684,0
+DA:687,0
+DA:690,0
+DA:693,0
+DA:696,0
+DA:699,0
+DA:702,0
+DA:705,0
+DA:708,0
+DA:711,0
+DA:714,0
+DA:717,0
+DA:720,0
+DA:723,0
+DA:726,0
+DA:729,0
+DA:732,0
+DA:735,0
+DA:738,0
+DA:740,0
+DA:743,0
+DA:745,0
+DA:748,0
+DA:751,0
+DA:754,0
+DA:757,0
+DA:760,0
+DA:763,0
+DA:766,0
+DA:769,0
+DA:772,0
+DA:775,0
+DA:778,0
+DA:781,0
+DA:784,0
+DA:787,0
+DA:789,0
+DA:792,0
+DA:795,0
+DA:797,0
+DA:800,0
+DA:803,0
+DA:806,0
+DA:808,0
+DA:810,0
+DA:815,0
+DA:818,0
+DA:821,0
+DA:824,0
+DA:827,0
+DA:830,0
+DA:833,0
+DA:836,0
+DA:839,0
+DA:842,0
+DA:845,0
+DA:848,0
+DA:851,0
+DA:854,0
+DA:857,0
+DA:860,0
+LF:295
LH:0
end_of_record
-SF:lib\l10n\app_localizations_es.dart
-DA:5,0
+SF:lib\l10n\app_localizations_de.dart
DA:7,0
-DA:10,0
-DA:13,0
-DA:16,0
-DA:19,0
-DA:22,0
-DA:25,0
-DA:28,0
-DA:31,0
-DA:34,0
-DA:37,0
-DA:40,0
-DA:43,0
-DA:46,0
-DA:49,0
-DA:52,0
-DA:55,0
-DA:58,0
-DA:61,0
-DA:64,0
-DA:67,0
-DA:70,0
+DA:9,0
+DA:12,0
+DA:15,0
+DA:18,0
+DA:21,0
+DA:24,0
+DA:27,0
+DA:30,0
+DA:33,0
+DA:36,0
+DA:39,0
+DA:42,0
+DA:45,0
+DA:48,0
+DA:51,0
+DA:54,0
+DA:57,0
+DA:60,0
+DA:63,0
+DA:66,0
+DA:69,0
DA:72,0
DA:75,0
DA:78,0
DA:81,0
-DA:83,0
-DA:86,0
-DA:89,0
-DA:92,0
-DA:95,0
-DA:98,0
-DA:101,0
-DA:104,0
+DA:84,0
+DA:87,0
+DA:90,0
+DA:93,0
+DA:96,0
+DA:99,0
+DA:102,0
+DA:105,0
DA:107,0
DA:110,0
DA:113,0
DA:116,0
DA:119,0
DA:122,0
-DA:125,0
-DA:128,0
-DA:131,0
+DA:124,0
+DA:127,0
+DA:130,0
DA:133,0
DA:136,0
DA:139,0
-DA:141,0
-DA:144,0
-DA:146,0
-DA:149,0
-DA:152,0
-DA:155,0
-DA:158,0
-DA:161,0
-DA:164,0
-DA:167,0
-DA:170,0
-DA:173,0
-DA:176,0
-DA:179,0
+DA:142,0
+DA:145,0
+DA:148,0
+DA:151,0
+DA:154,0
+DA:157,0
+DA:160,0
+DA:163,0
+DA:166,0
+DA:169,0
+DA:172,0
+DA:175,0
+DA:177,0
+DA:180,0
DA:182,0
DA:185,0
DA:188,0
-DA:191,0
-DA:194,0
-DA:197,0
-DA:200,0
-DA:203,0
-DA:206,0
-DA:209,0
+DA:190,0
+DA:193,0
+DA:195,0
+DA:198,0
+DA:201,0
+DA:204,0
+DA:207,0
+DA:210,0
DA:212,0
DA:215,0
DA:218,0
DA:221,0
DA:224,0
DA:227,0
-DA:229,0
-DA:232,0
-DA:235,0
-DA:238,0
-DA:241,0
-DA:244,0
-DA:247,0
-DA:250,0
-DA:253,0
-DA:256,0
-DA:259,0
-DA:262,0
-DA:265,0
-DA:268,0
-DA:271,0
-DA:274,0
-DA:277,0
-DA:280,0
-DA:283,0
-DA:286,0
-DA:289,0
-DA:292,0
-DA:295,0
+DA:230,0
+DA:233,0
+DA:236,0
+DA:239,0
+DA:242,0
+DA:245,0
+DA:248,0
+DA:251,0
+DA:254,0
+DA:257,0
+DA:260,0
+DA:263,0
+DA:266,0
+DA:269,0
+DA:272,0
+DA:275,0
+DA:278,0
+DA:281,0
+DA:284,0
+DA:287,0
+DA:290,0
+DA:293,0
+DA:296,0
DA:298,0
DA:301,0
DA:304,0
@@ -757,118 +828,280 @@ DA:361,0
DA:364,0
DA:367,0
DA:370,0
-DA:372,0
-DA:375,0
-DA:377,0
-DA:380,0
-DA:383,0
-DA:386,0
-DA:389,0
-DA:392,0
-LF:133
+DA:373,0
+DA:376,0
+DA:379,0
+DA:382,0
+DA:385,0
+DA:388,0
+DA:391,0
+DA:394,0
+DA:397,0
+DA:400,0
+DA:403,0
+DA:406,0
+DA:409,0
+DA:412,0
+DA:415,0
+DA:418,0
+DA:421,0
+DA:424,0
+DA:427,0
+DA:430,0
+DA:433,0
+DA:436,0
+DA:439,0
+DA:442,0
+DA:445,0
+DA:448,0
+DA:450,0
+DA:453,0
+DA:456,0
+DA:458,0
+DA:461,0
+DA:464,0
+DA:467,0
+DA:470,0
+DA:473,0
+DA:476,0
+DA:479,0
+DA:482,0
+DA:485,0
+DA:488,0
+DA:491,0
+DA:494,0
+DA:497,0
+DA:500,0
+DA:503,0
+DA:506,0
+DA:509,0
+DA:512,0
+DA:515,0
+DA:518,0
+DA:521,0
+DA:524,0
+DA:527,0
+DA:530,0
+DA:533,0
+DA:536,0
+DA:539,0
+DA:542,0
+DA:545,0
+DA:548,0
+DA:550,0
+DA:553,0
+DA:556,0
+DA:559,0
+DA:562,0
+DA:565,0
+DA:568,0
+DA:571,0
+DA:574,0
+DA:577,0
+DA:580,0
+DA:583,0
+DA:586,0
+DA:589,0
+DA:592,0
+DA:594,0
+DA:597,0
+DA:599,0
+DA:602,0
+DA:604,0
+DA:607,0
+DA:609,0
+DA:612,0
+DA:614,0
+DA:616,0
+DA:617,0
+DA:621,0
+DA:624,0
+DA:626,0
+DA:628,0
+DA:629,0
+DA:633,0
+DA:636,0
+DA:638,0
+DA:640,0
+DA:645,0
+DA:648,0
+DA:650,0
+DA:652,0
+DA:653,0
+DA:657,0
+DA:660,0
+DA:663,0
+DA:666,0
+DA:669,0
+DA:672,0
+DA:675,0
+DA:678,0
+DA:681,0
+DA:684,0
+DA:687,0
+DA:690,0
+DA:693,0
+DA:696,0
+DA:699,0
+DA:702,0
+DA:705,0
+DA:708,0
+DA:711,0
+DA:714,0
+DA:717,0
+DA:720,0
+DA:723,0
+DA:726,0
+DA:729,0
+DA:732,0
+DA:735,0
+DA:738,0
+DA:740,0
+DA:743,0
+DA:745,0
+DA:748,0
+DA:751,0
+DA:754,0
+DA:757,0
+DA:760,0
+DA:763,0
+DA:766,0
+DA:769,0
+DA:772,0
+DA:775,0
+DA:778,0
+DA:781,0
+DA:784,0
+DA:787,0
+DA:789,0
+DA:792,0
+DA:795,0
+DA:797,0
+DA:800,0
+DA:803,0
+DA:806,0
+DA:808,0
+DA:810,0
+DA:815,0
+DA:818,0
+DA:821,0
+DA:824,0
+DA:827,0
+DA:830,0
+DA:833,0
+DA:836,0
+DA:839,0
+DA:842,0
+DA:845,0
+DA:848,0
+DA:851,0
+DA:854,0
+DA:857,0
+DA:860,0
+LF:295
LH:0
end_of_record
-SF:lib\l10n\app_localizations_fr.dart
-DA:5,0
+SF:lib\l10n\app_localizations_en.dart
DA:7,0
-DA:10,0
-DA:13,0
-DA:16,0
-DA:19,0
-DA:22,0
-DA:25,0
-DA:28,0
-DA:31,0
-DA:34,0
-DA:37,0
-DA:40,0
-DA:43,0
-DA:46,0
-DA:49,0
-DA:52,0
-DA:55,0
-DA:58,0
-DA:61,0
-DA:64,0
-DA:67,0
-DA:70,0
+DA:9,0
+DA:12,0
+DA:15,0
+DA:18,0
+DA:21,0
+DA:24,0
+DA:27,0
+DA:30,0
+DA:33,0
+DA:36,0
+DA:39,0
+DA:42,0
+DA:45,0
+DA:48,0
+DA:51,0
+DA:54,0
+DA:57,0
+DA:60,0
+DA:63,0
+DA:66,0
+DA:69,0
DA:72,0
DA:75,0
DA:78,0
DA:81,0
-DA:83,0
-DA:86,0
-DA:89,0
-DA:92,0
-DA:95,0
-DA:98,0
-DA:101,0
-DA:104,0
+DA:84,0
+DA:87,0
+DA:90,0
+DA:93,0
+DA:96,0
+DA:99,0
+DA:102,0
+DA:105,0
DA:107,0
DA:110,0
DA:113,0
DA:116,0
DA:119,0
DA:122,0
-DA:125,0
-DA:128,0
-DA:131,0
+DA:124,0
+DA:127,0
+DA:130,0
DA:133,0
DA:136,0
DA:139,0
-DA:141,0
-DA:144,0
-DA:146,0
-DA:149,0
-DA:152,0
-DA:155,0
-DA:158,0
-DA:161,0
-DA:164,0
-DA:167,0
-DA:170,0
-DA:173,0
-DA:176,0
-DA:179,0
+DA:142,0
+DA:145,0
+DA:148,0
+DA:151,0
+DA:154,0
+DA:157,0
+DA:160,0
+DA:163,0
+DA:166,0
+DA:169,0
+DA:172,0
+DA:175,0
+DA:177,0
+DA:180,0
DA:182,0
DA:185,0
DA:188,0
-DA:191,0
-DA:194,0
-DA:197,0
-DA:200,0
-DA:203,0
-DA:206,0
-DA:209,0
+DA:190,0
+DA:193,0
+DA:195,0
+DA:198,0
+DA:201,0
+DA:204,0
+DA:207,0
+DA:210,0
DA:212,0
DA:215,0
DA:218,0
DA:221,0
DA:224,0
DA:227,0
-DA:229,0
-DA:232,0
-DA:235,0
-DA:238,0
-DA:241,0
-DA:244,0
-DA:247,0
-DA:250,0
-DA:253,0
-DA:256,0
-DA:259,0
-DA:262,0
-DA:265,0
-DA:268,0
-DA:271,0
-DA:274,0
-DA:277,0
-DA:280,0
-DA:283,0
-DA:286,0
-DA:289,0
-DA:292,0
-DA:295,0
+DA:230,0
+DA:233,0
+DA:236,0
+DA:239,0
+DA:242,0
+DA:245,0
+DA:248,0
+DA:251,0
+DA:254,0
+DA:257,0
+DA:260,0
+DA:263,0
+DA:266,0
+DA:269,0
+DA:272,0
+DA:275,0
+DA:278,0
+DA:281,0
+DA:284,0
+DA:287,0
+DA:290,0
+DA:293,0
+DA:296,0
DA:298,0
DA:301,0
DA:304,0
@@ -894,117 +1127,280 @@ DA:361,0
DA:364,0
DA:367,0
DA:370,0
-DA:372,0
-DA:375,0
-DA:377,0
-DA:380,0
-DA:383,0
-DA:386,0
-DA:389,0
-DA:392,0
-LF:133
+DA:373,0
+DA:376,0
+DA:379,0
+DA:382,0
+DA:385,0
+DA:388,0
+DA:391,0
+DA:394,0
+DA:397,0
+DA:400,0
+DA:403,0
+DA:406,0
+DA:409,0
+DA:412,0
+DA:415,0
+DA:418,0
+DA:421,0
+DA:424,0
+DA:427,0
+DA:430,0
+DA:433,0
+DA:436,0
+DA:439,0
+DA:442,0
+DA:445,0
+DA:448,0
+DA:450,0
+DA:453,0
+DA:456,0
+DA:458,0
+DA:461,0
+DA:464,0
+DA:467,0
+DA:470,0
+DA:473,0
+DA:476,0
+DA:479,0
+DA:482,0
+DA:485,0
+DA:488,0
+DA:491,0
+DA:494,0
+DA:497,0
+DA:500,0
+DA:503,0
+DA:506,0
+DA:509,0
+DA:512,0
+DA:515,0
+DA:518,0
+DA:521,0
+DA:524,0
+DA:527,0
+DA:530,0
+DA:533,0
+DA:536,0
+DA:539,0
+DA:542,0
+DA:545,0
+DA:548,0
+DA:550,0
+DA:553,0
+DA:556,0
+DA:559,0
+DA:562,0
+DA:565,0
+DA:568,0
+DA:571,0
+DA:574,0
+DA:577,0
+DA:580,0
+DA:583,0
+DA:586,0
+DA:589,0
+DA:592,0
+DA:594,0
+DA:597,0
+DA:599,0
+DA:602,0
+DA:604,0
+DA:607,0
+DA:609,0
+DA:612,0
+DA:614,0
+DA:616,0
+DA:617,0
+DA:621,0
+DA:624,0
+DA:626,0
+DA:628,0
+DA:629,0
+DA:633,0
+DA:636,0
+DA:638,0
+DA:640,0
+DA:645,0
+DA:648,0
+DA:650,0
+DA:652,0
+DA:653,0
+DA:657,0
+DA:660,0
+DA:663,0
+DA:666,0
+DA:669,0
+DA:672,0
+DA:675,0
+DA:678,0
+DA:681,0
+DA:684,0
+DA:687,0
+DA:690,0
+DA:693,0
+DA:696,0
+DA:699,0
+DA:702,0
+DA:705,0
+DA:708,0
+DA:711,0
+DA:714,0
+DA:717,0
+DA:720,0
+DA:723,0
+DA:726,0
+DA:729,0
+DA:732,0
+DA:735,0
+DA:738,0
+DA:740,0
+DA:743,0
+DA:745,0
+DA:748,0
+DA:751,0
+DA:754,0
+DA:757,0
+DA:760,0
+DA:763,0
+DA:766,0
+DA:769,0
+DA:772,0
+DA:775,0
+DA:778,0
+DA:781,0
+DA:784,0
+DA:787,0
+DA:789,0
+DA:792,0
+DA:795,0
+DA:797,0
+DA:800,0
+DA:803,0
+DA:806,0
+DA:808,0
+DA:810,0
+DA:815,0
+DA:818,0
+DA:821,0
+DA:824,0
+DA:827,0
+DA:830,0
+DA:833,0
+DA:836,0
+DA:839,0
+DA:842,0
+DA:845,0
+DA:848,0
+DA:851,0
+DA:854,0
+DA:857,0
+DA:860,0
+LF:295
LH:0
end_of_record
-SF:lib\l10n\app_localizations_nl.dart
-DA:5,0
+SF:lib\l10n\app_localizations_es.dart
DA:7,0
-DA:10,0
-DA:13,0
-DA:16,0
-DA:19,0
-DA:22,0
-DA:25,0
-DA:28,0
-DA:31,0
-DA:34,0
-DA:37,0
-DA:40,0
-DA:43,0
-DA:46,0
-DA:49,0
-DA:52,0
-DA:55,0
-DA:58,0
-DA:61,0
-DA:64,0
-DA:67,0
-DA:70,0
+DA:9,0
+DA:12,0
+DA:15,0
+DA:18,0
+DA:21,0
+DA:24,0
+DA:27,0
+DA:30,0
+DA:33,0
+DA:36,0
+DA:39,0
+DA:42,0
+DA:45,0
+DA:48,0
+DA:51,0
+DA:54,0
+DA:57,0
+DA:60,0
+DA:63,0
+DA:66,0
+DA:69,0
DA:72,0
DA:75,0
DA:78,0
DA:81,0
-DA:83,0
-DA:86,0
-DA:89,0
-DA:92,0
-DA:95,0
-DA:98,0
-DA:101,0
-DA:104,0
+DA:84,0
+DA:87,0
+DA:90,0
+DA:93,0
+DA:96,0
+DA:99,0
+DA:102,0
+DA:105,0
DA:107,0
DA:110,0
DA:113,0
DA:116,0
DA:119,0
DA:122,0
-DA:125,0
-DA:128,0
-DA:131,0
+DA:124,0
+DA:127,0
+DA:130,0
DA:133,0
DA:136,0
DA:139,0
-DA:144,0
-DA:146,0
-DA:149,0
-DA:152,0
-DA:155,0
-DA:158,0
-DA:161,0
-DA:164,0
-DA:167,0
-DA:170,0
-DA:173,0
-DA:176,0
-DA:179,0
+DA:142,0
+DA:145,0
+DA:148,0
+DA:151,0
+DA:154,0
+DA:157,0
+DA:160,0
+DA:163,0
+DA:166,0
+DA:169,0
+DA:172,0
+DA:175,0
+DA:177,0
+DA:180,0
DA:182,0
DA:185,0
DA:188,0
-DA:191,0
-DA:194,0
-DA:197,0
-DA:200,0
-DA:203,0
-DA:206,0
-DA:209,0
+DA:190,0
+DA:193,0
+DA:195,0
+DA:198,0
+DA:201,0
+DA:204,0
+DA:207,0
+DA:210,0
DA:212,0
DA:215,0
DA:218,0
DA:221,0
DA:224,0
DA:227,0
-DA:229,0
-DA:232,0
-DA:235,0
-DA:238,0
-DA:241,0
-DA:244,0
-DA:247,0
-DA:250,0
-DA:253,0
-DA:256,0
-DA:259,0
-DA:262,0
-DA:265,0
-DA:268,0
-DA:271,0
-DA:274,0
-DA:277,0
-DA:280,0
-DA:283,0
-DA:286,0
-DA:289,0
-DA:292,0
-DA:295,0
+DA:230,0
+DA:233,0
+DA:236,0
+DA:239,0
+DA:242,0
+DA:245,0
+DA:248,0
+DA:251,0
+DA:254,0
+DA:257,0
+DA:260,0
+DA:263,0
+DA:266,0
+DA:269,0
+DA:272,0
+DA:275,0
+DA:278,0
+DA:281,0
+DA:284,0
+DA:287,0
+DA:290,0
+DA:293,0
+DA:296,0
DA:298,0
DA:301,0
DA:304,0
@@ -1030,131 +1426,294 @@ DA:361,0
DA:364,0
DA:367,0
DA:370,0
-DA:372,0
-DA:375,0
-DA:377,0
-DA:380,0
-DA:383,0
-DA:386,0
-DA:389,0
-DA:392,0
-LF:132
+DA:373,0
+DA:376,0
+DA:379,0
+DA:382,0
+DA:385,0
+DA:388,0
+DA:391,0
+DA:394,0
+DA:397,0
+DA:400,0
+DA:403,0
+DA:406,0
+DA:409,0
+DA:412,0
+DA:415,0
+DA:418,0
+DA:421,0
+DA:424,0
+DA:427,0
+DA:430,0
+DA:433,0
+DA:436,0
+DA:439,0
+DA:442,0
+DA:445,0
+DA:448,0
+DA:450,0
+DA:453,0
+DA:456,0
+DA:458,0
+DA:461,0
+DA:464,0
+DA:467,0
+DA:470,0
+DA:473,0
+DA:476,0
+DA:479,0
+DA:482,0
+DA:485,0
+DA:488,0
+DA:491,0
+DA:494,0
+DA:497,0
+DA:500,0
+DA:503,0
+DA:506,0
+DA:509,0
+DA:512,0
+DA:515,0
+DA:518,0
+DA:521,0
+DA:524,0
+DA:527,0
+DA:530,0
+DA:533,0
+DA:536,0
+DA:539,0
+DA:542,0
+DA:545,0
+DA:548,0
+DA:550,0
+DA:553,0
+DA:556,0
+DA:559,0
+DA:562,0
+DA:565,0
+DA:568,0
+DA:571,0
+DA:574,0
+DA:577,0
+DA:580,0
+DA:583,0
+DA:586,0
+DA:589,0
+DA:592,0
+DA:594,0
+DA:597,0
+DA:599,0
+DA:602,0
+DA:604,0
+DA:607,0
+DA:609,0
+DA:612,0
+DA:614,0
+DA:616,0
+DA:617,0
+DA:621,0
+DA:624,0
+DA:626,0
+DA:628,0
+DA:629,0
+DA:633,0
+DA:636,0
+DA:638,0
+DA:640,0
+DA:645,0
+DA:648,0
+DA:650,0
+DA:652,0
+DA:653,0
+DA:657,0
+DA:660,0
+DA:663,0
+DA:666,0
+DA:669,0
+DA:672,0
+DA:675,0
+DA:678,0
+DA:681,0
+DA:684,0
+DA:687,0
+DA:690,0
+DA:693,0
+DA:696,0
+DA:699,0
+DA:702,0
+DA:705,0
+DA:708,0
+DA:711,0
+DA:714,0
+DA:717,0
+DA:720,0
+DA:723,0
+DA:726,0
+DA:729,0
+DA:732,0
+DA:735,0
+DA:738,0
+DA:740,0
+DA:743,0
+DA:745,0
+DA:748,0
+DA:751,0
+DA:754,0
+DA:757,0
+DA:760,0
+DA:763,0
+DA:766,0
+DA:769,0
+DA:772,0
+DA:775,0
+DA:778,0
+DA:781,0
+DA:784,0
+DA:787,0
+DA:789,0
+DA:792,0
+DA:795,0
+DA:797,0
+DA:800,0
+DA:803,0
+DA:806,0
+DA:808,0
+DA:810,0
+DA:815,0
+DA:818,0
+DA:821,0
+DA:824,0
+DA:827,0
+DA:830,0
+DA:833,0
+DA:836,0
+DA:839,0
+DA:842,0
+DA:845,0
+DA:848,0
+DA:851,0
+DA:854,0
+DA:857,0
+DA:860,0
+LF:295
LH:0
end_of_record
-SF:lib\l10n\app_localizations_pl.dart
-DA:5,0
+SF:lib\l10n\app_localizations_fr.dart
DA:7,0
-DA:10,0
-DA:13,0
-DA:16,0
-DA:19,0
-DA:22,0
-DA:25,0
-DA:28,0
-DA:31,0
-DA:34,0
-DA:37,0
-DA:40,0
-DA:43,0
-DA:46,0
-DA:49,0
-DA:52,0
-DA:55,0
-DA:58,0
-DA:61,0
-DA:64,0
-DA:67,0
-DA:70,0
+DA:9,0
+DA:12,0
+DA:15,0
+DA:18,0
+DA:21,0
+DA:24,0
+DA:27,0
+DA:30,0
+DA:33,0
+DA:36,0
+DA:39,0
+DA:42,0
+DA:45,0
+DA:48,0
+DA:51,0
+DA:54,0
+DA:57,0
+DA:60,0
+DA:63,0
+DA:66,0
+DA:69,0
DA:72,0
DA:75,0
DA:78,0
DA:81,0
-DA:83,0
-DA:86,0
-DA:89,0
-DA:92,0
-DA:95,0
-DA:98,0
-DA:101,0
-DA:104,0
+DA:84,0
+DA:87,0
+DA:90,0
+DA:93,0
+DA:96,0
+DA:99,0
+DA:102,0
+DA:105,0
DA:107,0
DA:110,0
DA:113,0
DA:116,0
DA:119,0
DA:122,0
-DA:125,0
-DA:128,0
-DA:131,0
+DA:124,0
+DA:127,0
+DA:130,0
DA:133,0
DA:136,0
DA:139,0
-DA:144,0
-DA:146,0
-DA:149,0
-DA:152,0
-DA:155,0
-DA:158,0
-DA:161,0
-DA:164,0
-DA:167,0
-DA:170,0
-DA:173,0
-DA:176,0
-DA:179,0
+DA:142,0
+DA:145,0
+DA:148,0
+DA:151,0
+DA:154,0
+DA:157,0
+DA:160,0
+DA:163,0
+DA:166,0
+DA:169,0
+DA:172,0
+DA:175,0
+DA:177,0
+DA:180,0
DA:182,0
DA:185,0
DA:188,0
-DA:191,0
-DA:194,0
-DA:197,0
-DA:200,0
-DA:203,0
-DA:206,0
-DA:209,0
+DA:190,0
+DA:193,0
+DA:195,0
+DA:198,0
+DA:201,0
+DA:204,0
+DA:207,0
+DA:210,0
DA:212,0
DA:215,0
DA:218,0
DA:221,0
DA:224,0
DA:227,0
-DA:229,0
-DA:232,0
-DA:235,0
-DA:238,0
-DA:241,0
-DA:244,0
-DA:247,0
-DA:250,0
-DA:253,0
-DA:256,0
-DA:259,0
-DA:262,0
-DA:265,0
-DA:268,0
-DA:271,0
-DA:274,0
-DA:277,0
-DA:280,0
-DA:283,0
-DA:286,0
-DA:289,0
-DA:292,0
-DA:295,0
-DA:298,0
-DA:301,0
-DA:304,0
-DA:307,0
-DA:310,0
-DA:313,0
-DA:316,0
-DA:319,0
-DA:322,0
-DA:325,0
-DA:328,0
-DA:331,0
-DA:334,0
-DA:337,0
+DA:230,0
+DA:233,0
+DA:236,0
+DA:239,0
+DA:242,0
+DA:245,0
+DA:248,0
+DA:251,0
+DA:254,0
+DA:257,0
+DA:260,0
+DA:263,0
+DA:266,0
+DA:269,0
+DA:272,0
+DA:275,0
+DA:278,0
+DA:281,0
+DA:284,0
+DA:287,0
+DA:290,0
+DA:293,0
+DA:296,0
+DA:298,0
+DA:301,0
+DA:304,0
+DA:307,0
+DA:310,0
+DA:313,0
+DA:316,0
+DA:319,0
+DA:322,0
+DA:325,0
+DA:328,0
+DA:331,0
+DA:334,0
+DA:337,0
DA:340,0
DA:343,0
DA:346,0
@@ -1166,1995 +1725,9865 @@ DA:361,0
DA:364,0
DA:367,0
DA:370,0
-DA:372,0
-DA:375,0
-DA:377,0
-DA:380,0
-DA:383,0
-DA:386,0
-DA:389,0
-DA:392,0
-LF:132
-LH:0
-end_of_record
-SF:lib\model\platform_info\platform_info_imp\dummy_platform_info.dart
-DA:5,0
-DA:8,0
-DA:11,0
-DA:14,0
-DA:17,0
-DA:20,0
-LF:6
+DA:373,0
+DA:376,0
+DA:379,0
+DA:382,0
+DA:385,0
+DA:388,0
+DA:391,0
+DA:394,0
+DA:397,0
+DA:400,0
+DA:403,0
+DA:406,0
+DA:409,0
+DA:412,0
+DA:415,0
+DA:418,0
+DA:421,0
+DA:424,0
+DA:427,0
+DA:430,0
+DA:433,0
+DA:436,0
+DA:439,0
+DA:442,0
+DA:445,0
+DA:448,0
+DA:450,0
+DA:453,0
+DA:456,0
+DA:458,0
+DA:461,0
+DA:464,0
+DA:467,0
+DA:470,0
+DA:473,0
+DA:476,0
+DA:479,0
+DA:482,0
+DA:485,0
+DA:488,0
+DA:491,0
+DA:494,0
+DA:497,0
+DA:500,0
+DA:503,0
+DA:506,0
+DA:509,0
+DA:512,0
+DA:515,0
+DA:518,0
+DA:521,0
+DA:524,0
+DA:527,0
+DA:530,0
+DA:533,0
+DA:536,0
+DA:539,0
+DA:542,0
+DA:545,0
+DA:548,0
+DA:550,0
+DA:553,0
+DA:556,0
+DA:559,0
+DA:562,0
+DA:565,0
+DA:568,0
+DA:571,0
+DA:574,0
+DA:577,0
+DA:580,0
+DA:583,0
+DA:586,0
+DA:589,0
+DA:592,0
+DA:594,0
+DA:597,0
+DA:599,0
+DA:602,0
+DA:604,0
+DA:607,0
+DA:609,0
+DA:612,0
+DA:614,0
+DA:616,0
+DA:617,0
+DA:621,0
+DA:624,0
+DA:626,0
+DA:628,0
+DA:629,0
+DA:633,0
+DA:636,0
+DA:638,0
+DA:640,0
+DA:645,0
+DA:648,0
+DA:650,0
+DA:652,0
+DA:653,0
+DA:657,0
+DA:660,0
+DA:663,0
+DA:666,0
+DA:669,0
+DA:672,0
+DA:675,0
+DA:678,0
+DA:681,0
+DA:684,0
+DA:687,0
+DA:690,0
+DA:693,0
+DA:696,0
+DA:699,0
+DA:702,0
+DA:705,0
+DA:708,0
+DA:711,0
+DA:714,0
+DA:717,0
+DA:720,0
+DA:723,0
+DA:726,0
+DA:729,0
+DA:732,0
+DA:735,0
+DA:738,0
+DA:740,0
+DA:743,0
+DA:745,0
+DA:748,0
+DA:751,0
+DA:754,0
+DA:757,0
+DA:760,0
+DA:763,0
+DA:766,0
+DA:769,0
+DA:772,0
+DA:775,0
+DA:778,0
+DA:781,0
+DA:784,0
+DA:787,0
+DA:789,0
+DA:792,0
+DA:795,0
+DA:797,0
+DA:800,0
+DA:803,0
+DA:806,0
+DA:808,0
+DA:810,0
+DA:815,0
+DA:818,0
+DA:821,0
+DA:824,0
+DA:827,0
+DA:830,0
+DA:833,0
+DA:836,0
+DA:839,0
+DA:842,0
+DA:845,0
+DA:848,0
+DA:851,0
+DA:854,0
+DA:857,0
+DA:860,0
+LF:295
LH:0
end_of_record
-SF:lib\model\push_request.dart
-DA:20,4
-DA:33,16
-DA:34,13
-DA:37,1
-DA:49,1
-DA:50,1
-DA:51,1
-DA:52,1
-DA:53,1
-DA:54,1
-DA:55,1
-DA:56,1
-DA:57,1
-DA:58,1
-DA:59,0
-DA:63,4
-DA:64,7
-DA:66,1
-DA:67,2
-DA:69,2
-DA:71,6
-DA:72,8
-DA:73,4
-DA:74,4
-DA:77,2
-DA:79,2
-LF:26
-LH:25
-end_of_record
-SF:lib\model\push_request.g.dart
-DA:9,2
-DA:10,1
-DA:11,1
-DA:12,2
-DA:13,1
-DA:14,1
-DA:15,1
-DA:16,2
-DA:17,1
-DA:18,1
-DA:19,1
-DA:22,1
-DA:23,1
-DA:24,1
-DA:25,1
-DA:26,1
-DA:27,2
-DA:28,1
-DA:29,1
-DA:30,2
-DA:31,1
-DA:32,1
-DA:33,1
-LF:23
-LH:23
-end_of_record
-SF:lib\utils\riverpod_providers.dart
-DA:28,0
-DA:29,0
-DA:31,0
-DA:32,0
+SF:lib\l10n\app_localizations_nl.dart
+DA:7,0
+DA:9,0
+DA:12,0
+DA:15,0
+DA:18,0
+DA:21,0
+DA:24,0
+DA:27,0
+DA:30,0
DA:33,0
-DA:35,0
DA:36,0
-DA:38,0
DA:39,0
-DA:43,0
-DA:44,0
+DA:42,0
DA:45,0
-DA:46,0
-DA:47,0
DA:48,0
DA:51,0
DA:54,0
-DA:58,0
-DA:59,0
+DA:57,0
DA:60,0
-DA:62,0
DA:63,0
-DA:64,0
-DA:67,0
-DA:68,0
+DA:66,0
DA:69,0
-DA:70,0
-DA:74,0
-DA:77,0
-DA:83,0
+DA:72,0
+DA:75,0
+DA:78,0
+DA:81,0
DA:84,0
-DA:85,0
-DA:86,0
+DA:87,0
DA:90,0
-DA:91,0
-DA:94,0
-DA:95,0
+DA:93,0
DA:96,0
-DA:97,0
-DA:100,0
-DA:101,0
+DA:99,0
DA:102,0
-DA:103,0
-DA:104,0
DA:105,0
-DA:108,0
-DA:109,0
+DA:107,0
+DA:110,0
+DA:113,0
DA:116,0
-DA:118,0
DA:119,0
DA:122,0
-DA:123,0
DA:124,0
-DA:128,0
+DA:127,0
DA:130,0
-LF:55
-LH:0
-end_of_record
-SF:lib\model\push_request_queue.dart
-DA:10,4
-DA:15,4
-DA:16,8
-DA:17,4
-DA:20,2
-DA:21,2
-DA:22,0
-DA:25,2
-DA:28,0
-DA:30,0
-DA:32,3
-DA:34,0
-DA:36,6
-DA:38,2
-DA:39,12
-DA:41,4
-DA:44,3
-DA:46,3
-DA:48,0
-DA:50,12
-DA:52,5
-DA:54,6
-DA:56,1
-DA:58,2
-DA:61,2
-DA:62,14
-DA:64,2
-DA:65,6
-DA:67,7
-DA:68,3
-DA:74,0
-DA:75,0
-DA:77,4
-DA:79,4
-LF:34
-LH:27
-end_of_record
-SF:lib\model\push_request_queue.g.dart
-DA:9,2
-DA:10,2
-DA:11,4
-DA:12,4
-DA:13,2
-DA:15,2
-DA:16,2
-DA:17,2
-LF:8
-LH:8
-end_of_record
-SF:lib\model\tokens\push_token.dart
-DA:18,2
-DA:35,5
-DA:36,4
-DA:37,5
-DA:38,4
-DA:39,0
-DA:40,4
-DA:42,2
-DA:43,4
-DA:44,6
-DA:45,6
-DA:48,2
-DA:49,14
-DA:50,4
-DA:52,4
-DA:58,2
-DA:59,7
-DA:60,2
-DA:63,3
-DA:88,3
-DA:89,2
-DA:90,6
-DA:92,2
-DA:117,2
-DA:118,2
-DA:119,2
-DA:120,2
-DA:121,2
-DA:122,2
-DA:123,2
-DA:124,2
-DA:125,2
-DA:126,2
-DA:127,2
-DA:128,2
-DA:129,2
-DA:130,2
-DA:131,2
-DA:132,2
-DA:133,2
-DA:134,2
-DA:135,2
-DA:136,2
-DA:137,3
-DA:141,2
-DA:142,7
-DA:144,0
+DA:133,0
+DA:136,0
+DA:139,0
+DA:142,0
DA:145,0
-DA:147,1
-DA:149,2
-DA:150,1
-DA:151,2
-DA:152,1
-DA:153,2
-DA:154,1
-DA:155,1
-DA:156,1
-DA:157,1
-DA:158,1
-DA:159,1
-DA:160,1
-DA:161,1
-DA:164,1
-DA:167,1
-DA:168,1
-DA:169,1
-DA:170,1
-DA:171,1
-DA:172,1
-DA:173,5
-DA:174,1
-DA:175,1
-DA:176,1
-DA:177,1
-DA:178,1
-DA:181,0
-DA:186,1
-DA:187,1
-DA:188,2
-DA:189,1
-DA:190,1
-DA:191,1
-DA:192,0
+DA:148,0
+DA:151,0
+DA:154,0
+DA:157,0
+DA:160,0
+DA:163,0
+DA:166,0
+DA:169,0
+DA:172,0
+DA:175,0
+DA:177,0
+DA:180,0
+DA:182,0
+DA:185,0
+DA:188,0
DA:193,0
-DA:194,0
-DA:196,1
-DA:199,2
-LF:87
-LH:80
-end_of_record
-SF:lib\model\tokens\push_token.g.dart
-DA:9,2
-DA:10,1
-DA:11,1
-DA:12,1
-DA:13,1
-DA:14,3
-DA:15,1
-DA:17,2
-DA:18,1
-DA:19,1
-DA:20,1
-DA:21,1
-DA:22,1
-DA:23,1
-DA:24,1
-DA:25,1
-DA:26,1
-DA:28,1
-DA:29,1
-DA:30,1
-DA:32,1
-DA:33,1
-DA:34,1
-DA:35,1
-DA:36,1
-DA:37,1
-DA:38,1
-DA:39,1
-DA:42,2
-DA:43,1
-DA:44,1
-DA:45,1
-DA:46,1
-DA:47,1
-DA:48,1
-DA:49,1
-DA:50,1
-DA:51,1
-DA:52,2
-DA:53,1
-DA:54,1
-DA:55,1
-DA:56,2
-DA:57,1
-DA:58,2
-DA:59,1
-DA:60,1
-DA:61,1
-DA:62,1
-DA:63,1
-LF:50
-LH:50
+DA:195,0
+DA:198,0
+DA:201,0
+DA:204,0
+DA:207,0
+DA:210,0
+DA:212,0
+DA:215,0
+DA:218,0
+DA:221,0
+DA:224,0
+DA:227,0
+DA:230,0
+DA:233,0
+DA:236,0
+DA:239,0
+DA:242,0
+DA:245,0
+DA:248,0
+DA:251,0
+DA:254,0
+DA:257,0
+DA:260,0
+DA:263,0
+DA:266,0
+DA:269,0
+DA:272,0
+DA:275,0
+DA:278,0
+DA:281,0
+DA:284,0
+DA:287,0
+DA:290,0
+DA:293,0
+DA:296,0
+DA:298,0
+DA:301,0
+DA:304,0
+DA:307,0
+DA:310,0
+DA:313,0
+DA:316,0
+DA:319,0
+DA:322,0
+DA:325,0
+DA:328,0
+DA:331,0
+DA:334,0
+DA:337,0
+DA:340,0
+DA:343,0
+DA:346,0
+DA:349,0
+DA:352,0
+DA:355,0
+DA:358,0
+DA:361,0
+DA:364,0
+DA:367,0
+DA:370,0
+DA:373,0
+DA:376,0
+DA:379,0
+DA:382,0
+DA:385,0
+DA:388,0
+DA:391,0
+DA:394,0
+DA:397,0
+DA:400,0
+DA:403,0
+DA:406,0
+DA:409,0
+DA:412,0
+DA:415,0
+DA:418,0
+DA:421,0
+DA:424,0
+DA:427,0
+DA:430,0
+DA:433,0
+DA:436,0
+DA:439,0
+DA:442,0
+DA:445,0
+DA:448,0
+DA:450,0
+DA:453,0
+DA:456,0
+DA:458,0
+DA:461,0
+DA:464,0
+DA:467,0
+DA:470,0
+DA:473,0
+DA:476,0
+DA:479,0
+DA:482,0
+DA:485,0
+DA:488,0
+DA:491,0
+DA:494,0
+DA:497,0
+DA:500,0
+DA:503,0
+DA:506,0
+DA:509,0
+DA:512,0
+DA:515,0
+DA:518,0
+DA:521,0
+DA:524,0
+DA:527,0
+DA:530,0
+DA:533,0
+DA:536,0
+DA:539,0
+DA:542,0
+DA:545,0
+DA:548,0
+DA:550,0
+DA:553,0
+DA:556,0
+DA:559,0
+DA:562,0
+DA:565,0
+DA:568,0
+DA:571,0
+DA:574,0
+DA:577,0
+DA:580,0
+DA:583,0
+DA:586,0
+DA:589,0
+DA:592,0
+DA:594,0
+DA:597,0
+DA:599,0
+DA:602,0
+DA:604,0
+DA:607,0
+DA:609,0
+DA:612,0
+DA:614,0
+DA:616,0
+DA:617,0
+DA:621,0
+DA:624,0
+DA:626,0
+DA:628,0
+DA:629,0
+DA:633,0
+DA:636,0
+DA:638,0
+DA:640,0
+DA:645,0
+DA:648,0
+DA:650,0
+DA:652,0
+DA:653,0
+DA:657,0
+DA:660,0
+DA:663,0
+DA:666,0
+DA:669,0
+DA:672,0
+DA:675,0
+DA:678,0
+DA:681,0
+DA:684,0
+DA:687,0
+DA:690,0
+DA:693,0
+DA:696,0
+DA:699,0
+DA:702,0
+DA:705,0
+DA:708,0
+DA:711,0
+DA:714,0
+DA:717,0
+DA:720,0
+DA:723,0
+DA:726,0
+DA:729,0
+DA:732,0
+DA:735,0
+DA:738,0
+DA:740,0
+DA:743,0
+DA:745,0
+DA:748,0
+DA:751,0
+DA:754,0
+DA:757,0
+DA:760,0
+DA:763,0
+DA:766,0
+DA:769,0
+DA:772,0
+DA:775,0
+DA:778,0
+DA:781,0
+DA:784,0
+DA:787,0
+DA:789,0
+DA:792,0
+DA:795,0
+DA:797,0
+DA:800,0
+DA:803,0
+DA:806,0
+DA:808,0
+DA:810,0
+DA:815,0
+DA:818,0
+DA:821,0
+DA:824,0
+DA:827,0
+DA:830,0
+DA:833,0
+DA:836,0
+DA:839,0
+DA:842,0
+DA:845,0
+DA:848,0
+DA:851,0
+DA:854,0
+DA:857,0
+DA:860,0
+LF:294
+LH:0
end_of_record
-SF:lib\model\tokens\day_password_token.dart
-DA:19,1
-DA:34,2
-DA:35,2
-DA:37,0
-DA:53,0
+SF:lib\l10n\app_localizations_pl.dart
+DA:7,0
+DA:9,0
+DA:12,0
+DA:15,0
+DA:18,0
+DA:21,0
+DA:24,0
+DA:27,0
+DA:30,0
+DA:33,0
+DA:36,0
+DA:39,0
+DA:42,0
+DA:45,0
+DA:48,0
+DA:51,0
DA:54,0
-DA:55,0
-DA:56,0
DA:57,0
-DA:58,0
-DA:59,0
DA:60,0
-DA:61,0
-DA:62,0
DA:63,0
-DA:64,0
-DA:65,0
DA:66,0
-DA:67,0
-DA:70,1
-DA:71,1
-DA:72,1
-DA:73,2
-DA:74,1
-DA:75,2
-DA:76,2
-DA:80,0
+DA:69,0
+DA:72,0
+DA:75,0
+DA:78,0
DA:81,0
-DA:82,0
-DA:85,0
-DA:86,0
+DA:84,0
DA:87,0
-DA:89,0
-DA:92,0
+DA:90,0
DA:93,0
-DA:94,0
-DA:95,0
-DA:98,0
+DA:96,0
DA:99,0
-DA:100,0
-DA:101,0
DA:102,0
-DA:103,0
-DA:104,0
DA:105,0
-DA:106,0
DA:107,0
-DA:108,0
-DA:111,0
+DA:110,0
+DA:113,0
DA:116,0
-DA:117,0
DA:119,0
-DA:121,0
-LF:53
-LH:10
-end_of_record
-SF:lib\model\tokens\day_password_token.g.dart
-DA:9,0
-DA:10,0
-DA:11,0
-DA:12,0
-DA:13,0
-DA:14,0
-DA:15,0
-DA:16,0
-DA:17,0
-DA:18,0
-DA:19,0
-DA:21,0
-DA:22,0
-DA:23,0
-DA:24,0
-DA:25,0
-DA:26,0
-DA:29,0
-DA:30,0
-DA:31,0
-DA:32,0
-DA:33,0
-DA:34,0
-DA:35,0
-DA:36,0
-DA:37,0
-DA:38,0
-DA:39,0
-DA:40,0
-DA:41,0
-DA:42,0
-DA:43,0
-DA:44,0
-LF:33
-LH:0
-end_of_record
+DA:122,0
+DA:124,0
+DA:127,0
+DA:130,0
+DA:133,0
+DA:136,0
+DA:139,0
+DA:142,0
+DA:145,0
+DA:148,0
+DA:151,0
+DA:154,0
+DA:157,0
+DA:160,0
+DA:163,0
+DA:166,0
+DA:169,0
+DA:172,0
+DA:175,0
+DA:177,0
+DA:180,0
+DA:182,0
+DA:185,0
+DA:188,0
+DA:193,0
+DA:195,0
+DA:198,0
+DA:201,0
+DA:204,0
+DA:207,0
+DA:210,0
+DA:212,0
+DA:215,0
+DA:218,0
+DA:221,0
+DA:224,0
+DA:227,0
+DA:230,0
+DA:233,0
+DA:236,0
+DA:239,0
+DA:242,0
+DA:245,0
+DA:248,0
+DA:251,0
+DA:254,0
+DA:257,0
+DA:260,0
+DA:263,0
+DA:266,0
+DA:269,0
+DA:272,0
+DA:275,0
+DA:278,0
+DA:281,0
+DA:284,0
+DA:287,0
+DA:290,0
+DA:293,0
+DA:296,0
+DA:298,0
+DA:301,0
+DA:304,0
+DA:307,0
+DA:310,0
+DA:313,0
+DA:316,0
+DA:319,0
+DA:322,0
+DA:325,0
+DA:328,0
+DA:331,0
+DA:334,0
+DA:337,0
+DA:340,0
+DA:343,0
+DA:346,0
+DA:349,0
+DA:352,0
+DA:355,0
+DA:358,0
+DA:361,0
+DA:364,0
+DA:367,0
+DA:370,0
+DA:373,0
+DA:376,0
+DA:379,0
+DA:382,0
+DA:385,0
+DA:388,0
+DA:391,0
+DA:394,0
+DA:397,0
+DA:400,0
+DA:403,0
+DA:406,0
+DA:409,0
+DA:412,0
+DA:415,0
+DA:418,0
+DA:421,0
+DA:424,0
+DA:427,0
+DA:430,0
+DA:433,0
+DA:436,0
+DA:439,0
+DA:442,0
+DA:445,0
+DA:448,0
+DA:450,0
+DA:453,0
+DA:456,0
+DA:458,0
+DA:461,0
+DA:464,0
+DA:467,0
+DA:470,0
+DA:473,0
+DA:476,0
+DA:479,0
+DA:482,0
+DA:485,0
+DA:488,0
+DA:491,0
+DA:494,0
+DA:497,0
+DA:500,0
+DA:503,0
+DA:506,0
+DA:509,0
+DA:512,0
+DA:515,0
+DA:518,0
+DA:521,0
+DA:524,0
+DA:527,0
+DA:530,0
+DA:533,0
+DA:536,0
+DA:539,0
+DA:542,0
+DA:545,0
+DA:548,0
+DA:550,0
+DA:553,0
+DA:556,0
+DA:559,0
+DA:562,0
+DA:565,0
+DA:568,0
+DA:571,0
+DA:574,0
+DA:577,0
+DA:580,0
+DA:583,0
+DA:586,0
+DA:589,0
+DA:592,0
+DA:594,0
+DA:597,0
+DA:599,0
+DA:602,0
+DA:604,0
+DA:607,0
+DA:609,0
+DA:612,0
+DA:614,0
+DA:616,0
+DA:617,0
+DA:621,0
+DA:624,0
+DA:626,0
+DA:628,0
+DA:629,0
+DA:633,0
+DA:636,0
+DA:638,0
+DA:640,0
+DA:645,0
+DA:648,0
+DA:650,0
+DA:652,0
+DA:653,0
+DA:657,0
+DA:660,0
+DA:663,0
+DA:666,0
+DA:669,0
+DA:672,0
+DA:675,0
+DA:678,0
+DA:681,0
+DA:684,0
+DA:687,0
+DA:690,0
+DA:693,0
+DA:696,0
+DA:699,0
+DA:702,0
+DA:705,0
+DA:708,0
+DA:711,0
+DA:714,0
+DA:717,0
+DA:720,0
+DA:723,0
+DA:726,0
+DA:729,0
+DA:732,0
+DA:735,0
+DA:738,0
+DA:740,0
+DA:743,0
+DA:745,0
+DA:748,0
+DA:751,0
+DA:754,0
+DA:757,0
+DA:760,0
+DA:763,0
+DA:766,0
+DA:769,0
+DA:772,0
+DA:775,0
+DA:778,0
+DA:781,0
+DA:784,0
+DA:787,0
+DA:789,0
+DA:792,0
+DA:795,0
+DA:797,0
+DA:800,0
+DA:803,0
+DA:806,0
+DA:808,0
+DA:810,0
+DA:815,0
+DA:818,0
+DA:821,0
+DA:824,0
+DA:827,0
+DA:830,0
+DA:833,0
+DA:836,0
+DA:839,0
+DA:842,0
+DA:845,0
+DA:848,0
+DA:851,0
+DA:854,0
+DA:857,0
+DA:860,0
+LF:294
+LH:0
+end_of_record
+SF:lib\mains\main_netknights.dart
+DA:44,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:59,0
+DA:61,0
+DA:63,0
+DA:65,0
+DA:68,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:73,0
+DA:74,0
+DA:79,0
+DA:83,0
+DA:84,0
+DA:85,0
+DA:86,0
+DA:87,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:96,0
+DA:98,0
+DA:99,0
+DA:100,0
+DA:101,0
+DA:103,0
+DA:104,0
+DA:105,0
+DA:106,0
+LF:40
+LH:0
+end_of_record
+SF:lib\utils\app_customizer.dart
+DA:13,0
+DA:39,17
+DA:78,17
+DA:132,0
+DA:136,0
+DA:139,0
+DA:144,0
+DA:146,0
+DA:148,0
+DA:150,0
+DA:171,0
+DA:172,0
+DA:173,0
+DA:174,0
+DA:175,0
+DA:176,0
+DA:177,0
+DA:178,0
+DA:179,0
+DA:180,0
+DA:181,0
+DA:182,0
+DA:183,0
+DA:184,0
+DA:185,0
+DA:186,0
+DA:187,0
+DA:188,0
+DA:189,0
+DA:192,0
+DA:193,0
+DA:194,0
+DA:195,0
+DA:196,0
+DA:199,0
+DA:200,0
+DA:201,0
+DA:202,0
+DA:203,0
+DA:204,0
+DA:205,0
+DA:206,0
+DA:207,0
+DA:208,0
+DA:209,0
+DA:210,0
+DA:211,0
+DA:212,0
+DA:213,0
+DA:214,0
+DA:215,0
+DA:216,0
+DA:220,0
+DA:221,0
+DA:222,0
+DA:223,0
+DA:224,0
+DA:225,0
+DA:226,0
+DA:227,0
+DA:228,0
+DA:229,0
+DA:230,0
+DA:231,0
+DA:232,0
+DA:233,0
+DA:234,0
+DA:235,0
+DA:236,0
+DA:237,0
+DA:240,0
+DA:243,0
+DA:244,0
+DA:245,0
+DA:246,0
+DA:247,0
+DA:248,0
+DA:249,0
+DA:250,0
+DA:251,0
+DA:252,0
+DA:253,0
+DA:254,0
+DA:255,0
+DA:256,0
+DA:257,0
+DA:258,0
+DA:259,0
+DA:260,0
+DA:263,0
+DA:265,0
+DA:266,0
+DA:267,0
+DA:268,0
+DA:269,0
+DA:270,0
+DA:271,0
+DA:272,0
+DA:273,0
+DA:274,0
+DA:275,0
+DA:276,0
+DA:277,0
+DA:278,0
+DA:279,0
+DA:280,0
+DA:281,0
+DA:283,0
+DA:284,0
+DA:285,0
+DA:288,0
+DA:289,0
+DA:290,0
+DA:291,0
+DA:293,0
+DA:294,0
+DA:298,0
+DA:299,0
+DA:300,0
+DA:302,0
+DA:303,0
+DA:304,0
+DA:305,0
+DA:309,0
+DA:310,0
+DA:311,0
+DA:312,0
+DA:313,0
+DA:314,0
+DA:316,0
+DA:317,0
+DA:319,0
+DA:320,0
+DA:323,0
+DA:324,0
+DA:325,0
+DA:326,0
+DA:327,0
+DA:328,0
+DA:331,0
+DA:332,0
+DA:333,0
+DA:336,0
+DA:337,0
+DA:338,0
+DA:341,0
+DA:343,0
+DA:344,0
+DA:345,0
+DA:347,0
+DA:348,0
+DA:349,0
+DA:350,0
+DA:351,0
+DA:352,0
+DA:353,0
+DA:354,0
+DA:356,0
+DA:357,0
+DA:358,0
+DA:359,0
+DA:360,0
+DA:361,0
+DA:362,0
+DA:364,0
+DA:365,0
+DA:366,0
+DA:367,0
+DA:370,0
+DA:371,0
+DA:376,0
+DA:377,0
+DA:378,0
+DA:381,0
+DA:382,0
+DA:387,0
+DA:388,0
+DA:389,0
+DA:392,0
+DA:393,0
+DA:397,0
+DA:398,0
+DA:401,0
+DA:402,0
+DA:407,0
+DA:408,0
+DA:409,0
+DA:410,0
+DA:411,0
+DA:412,0
+DA:414,0
+DA:415,0
+DA:416,0
+DA:418,0
+DA:419,0
+DA:459,0
+DA:460,0
+DA:465,0
+DA:468,0
+DA:469,0
+DA:475,0
+DA:485,0
+DA:495,0
+DA:496,0
+DA:497,0
+DA:498,0
+DA:499,0
+DA:500,0
+DA:501,0
+DA:502,0
+DA:505,0
+DA:507,0
+DA:509,0
+DA:510,0
+DA:511,0
+DA:512,0
+DA:513,0
+DA:514,0
+DA:515,0
+DA:516,0
+DA:519,0
+DA:520,0
+DA:521,0
+DA:522,0
+DA:523,0
+DA:524,0
+DA:525,0
+DA:526,0
+DA:536,0
+DA:543,0
+DA:547,0
+DA:549,0
+DA:554,0
+DA:555,0
+DA:556,0
+DA:559,0
+DA:560,0
+DA:561,0
+DA:570,0
+DA:577,0
+DA:578,0
+DA:579,0
+DA:580,0
+DA:581,0
+DA:582,0
+DA:585,0
+DA:586,0
+DA:587,0
+DA:588,0
+DA:589,0
+DA:590,0
+DA:597,0
+DA:598,0
+DA:601,0
+DA:604,0
+LF:255
+LH:2
+end_of_record
+SF:lib\utils\globals.dart
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:44,0
+DA:45,0
+DA:50,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:59,0
+DA:63,0
+DA:64,0
+LF:25
+LH:0
+end_of_record
+SF:lib\utils\logger.dart
+DA:22,0
+DA:26,0
+DA:28,0
+DA:29,0
+DA:30,12
+DA:31,4
+DA:39,4
+DA:41,4
+DA:42,4
+DA:47,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:52,0
+DA:55,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:72,0
+DA:73,0
+DA:74,4
+DA:76,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:86,4
+DA:91,0
+DA:97,12
+DA:98,4
+DA:99,12
+DA:104,0
+DA:106,0
+DA:108,0
+DA:113,4
+DA:114,8
+DA:115,4
+DA:116,8
+DA:117,0
+DA:119,4
+DA:122,1
+DA:123,2
+DA:124,1
+DA:125,2
+DA:126,0
+DA:128,1
+DA:131,0
+DA:132,0
+DA:133,0
+DA:135,0
+DA:137,0
+DA:139,0
+DA:140,0
+DA:142,0
+DA:144,0
+DA:145,0
+DA:147,0
+DA:150,0
+DA:151,0
+DA:152,0
+DA:153,0
+DA:154,0
+DA:157,0
+DA:158,0
+DA:160,0
+DA:162,0
+DA:164,0
+DA:167,0
+DA:168,0
+DA:171,0
+DA:172,0
+DA:173,0
+DA:174,0
+DA:175,0
+DA:177,0
+DA:179,0
+DA:182,0
+DA:184,0
+DA:187,0
+DA:188,0
+DA:191,0
+DA:192,0
+DA:193,0
+DA:194,0
+DA:195,0
+DA:196,0
+DA:197,0
+DA:198,0
+DA:208,4
+DA:209,4
+DA:210,4
+DA:211,4
+DA:214,4
+DA:215,8
+DA:219,0
+DA:220,0
+DA:221,0
+DA:222,0
+DA:223,0
+DA:224,0
+DA:225,0
+DA:226,0
+DA:229,0
+DA:230,0
+DA:233,0
+DA:237,4
+DA:238,8
+DA:241,4
+DA:242,8
+DA:243,0
+DA:244,0
+DA:247,4
+DA:248,0
+DA:249,0
+DA:254,8
+DA:255,4
+DA:257,0
+DA:258,0
+DA:259,0
+DA:260,0
+DA:262,4
+DA:265,4
+DA:270,4
+DA:272,8
+DA:275,4
+DA:277,8
+DA:280,0
+DA:282,0
+DA:283,0
+DA:284,0
+DA:285,0
+DA:290,0
+DA:291,0
+DA:292,0
+DA:293,0
+DA:294,0
+DA:295,0
+DA:296,0
+DA:298,0
+DA:299,0
+DA:300,0
+DA:301,0
+DA:302,0
+DA:311,0
+DA:312,0
+DA:313,0
+DA:314,0
+DA:315,0
+DA:316,0
+DA:323,4
+DA:324,8
+DA:326,12
+DA:327,4
+DA:332,4
+DA:333,12
+DA:334,8
+DA:335,4
+DA:336,5
+DA:337,5
+DA:339,4
+DA:341,12
+DA:342,4
+DA:343,20
+DA:344,20
+DA:345,12
+DA:351,12
+LF:166
+LH:56
+end_of_record
+SF:lib\utils\riverpod_providers.dart
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:41,0
+DA:43,0
+DA:46,0
+DA:47,0
+DA:55,0
+DA:56,0
+DA:58,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:72,0
+DA:73,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:79,0
+DA:81,0
+DA:82,0
+DA:86,0
+DA:87,0
+DA:88,0
+DA:89,0
+DA:98,0
+DA:99,0
+DA:100,0
+DA:101,0
+DA:102,0
+DA:103,0
+DA:105,0
+DA:106,0
+DA:121,0
+DA:122,0
+DA:123,0
+DA:124,0
+DA:129,0
+DA:130,0
+DA:131,0
+DA:137,0
+DA:139,0
+DA:140,0
+DA:141,0
+DA:142,0
+DA:143,0
+DA:144,0
+DA:145,0
+DA:146,0
+DA:147,0
+DA:148,0
+DA:153,0
+DA:157,0
+DA:158,0
+DA:159,0
+DA:164,0
+DA:165,0
+DA:166,0
+DA:167,0
+DA:171,0
+DA:172,0
+DA:173,0
+DA:178,0
+DA:179,0
+DA:180,0
+DA:181,0
+DA:182,0
+DA:184,0
+DA:189,0
+LF:73
+LH:0
+end_of_record
+SF:lib\views\add_token_manually_view\add_token_manually_view.dart
+DA:21,0
+DA:22,0
+DA:23,0
+DA:25,17
+DA:27,0
+DA:28,0
+DA:52,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:60,0
+DA:62,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:71,0
+DA:73,0
+DA:74,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:84,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:97,0
+DA:98,0
+DA:99,0
+DA:100,0
+DA:101,0
+DA:102,0
+DA:107,0
+DA:108,0
+DA:109,0
+DA:110,0
+DA:112,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:118,0
+DA:119,0
+DA:120,0
+DA:123,0
+DA:124,0
+DA:125,0
+DA:126,0
+DA:127,0
+DA:128,0
+DA:131,0
+DA:132,0
+DA:133,0
+DA:134,0
+DA:136,0
+DA:138,0
+DA:139,0
+DA:140,0
+DA:141,0
+DA:142,0
+DA:146,0
+DA:148,0
+DA:149,0
+DA:150,0
+DA:151,0
+DA:152,0
+DA:156,0
+DA:158,0
+DA:159,0
+DA:160,0
+DA:161,0
+DA:165,0
+DA:166,0
+DA:168,0
+DA:169,0
+DA:181,0
+DA:182,0
+DA:183,0
+DA:185,0
+DA:186,0
+DA:187,0
+DA:189,0
+DA:190,0
+DA:191,0
+DA:193,0
+DA:195,0
+DA:196,0
+DA:197,0
+DA:198,0
+DA:202,0
+DA:206,0
+DA:207,0
+DA:208,0
+DA:210,0
+DA:211,0
+DA:213,0
+DA:217,0
+DA:218,0
+DA:220,0
+DA:221,0
+DA:223,0
+LF:109
+LH:1
+end_of_record
+SF:lib\views\import_tokens_view\import_tokens_view.dart
+DA:12,0
+DA:23,17
+DA:25,0
+DA:26,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:42,0
+DA:45,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:51,0
+DA:53,0
+DA:55,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:66,0
+DA:68,0
+LF:27
+LH:1
+end_of_record
+SF:lib\views\license_view\license_view.dart
+DA:8,0
+DA:15,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:25,0
+DA:27,0
+DA:28,0
+LF:12
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view.dart
+DA:23,0
+DA:30,0
+DA:32,0
+DA:33,0
+DA:39,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:49,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:55,0
+DA:57,0
+DA:59,0
+DA:60,0
+DA:65,0
+DA:67,0
+DA:69,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:88,0
+DA:89,0
+DA:91,0
+DA:92,0
+DA:93,0
+LF:34
+LH:0
+end_of_record
+SF:lib\views\push_token_view\push_tokens_view.dart
+DA:8,0
+DA:11,17
+DA:13,0
+DA:15,0
+DA:17,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+LF:10
+LH:1
+end_of_record
+SF:lib\views\qr_scanner_view\qr_scanner_view.dart
+DA:34,17
+DA:36,0
+DA:37,0
+DA:39,0
+DA:44,0
+DA:46,0
+DA:48,0
+DA:55,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:77,0
+DA:78,0
+DA:80,0
+DA:84,0
+DA:85,0
+DA:86,0
+DA:87,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:97,0
+DA:100,0
+LF:36
+LH:1
+end_of_record
+SF:lib\views\settings_view\settings_view.dart
+DA:17,0
+DA:21,17
+DA:23,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:39,0
+DA:41,0
+DA:43,0
+DA:51,0
+LF:16
+LH:1
+end_of_record
+SF:lib\views\splash_screen\splash_screen.dart
+DA:23,0
+DA:25,0
+DA:26,0
+DA:28,0
+DA:30,0
+DA:34,0
+DA:47,0
+DA:49,0
+DA:50,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:73,0
+DA:77,0
+DA:79,0
+DA:80,0
+DA:83,0
+DA:86,0
+DA:87,0
+DA:88,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:102,0
+DA:105,0
+DA:106,0
+DA:107,0
+DA:108,0
+DA:109,0
+DA:112,0
+DA:113,0
+DA:114,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:124,0
+DA:125,0
+DA:127,0
+DA:128,0
+DA:131,0
+DA:133,0
+DA:135,0
+DA:136,0
+DA:137,0
+DA:138,0
+DA:140,0
+DA:142,0
+LF:61
+LH:0
+end_of_record
+SF:lib\widgets\app_wrapper.dart
+DA:19,0
+DA:21,0
+DA:23,0
+DA:29,0
+DA:31,0
+DA:32,0
+DA:38,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:51,0
+DA:52,0
+DA:54,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:61,0
+DA:62,0
+DA:64,0
+DA:65,0
+DA:67,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:80,0
+DA:82,0
+DA:83,0
+DA:86,0
+DA:88,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:94,0
+DA:95,0
+LF:45
+LH:0
+end_of_record
+SF:lib\model\enums\app_feature.dart
+DA:8,0
+DA:9,0
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+LF:7
+LH:0
+end_of_record
+SF:lib\utils\home_widget_utils.dart
+DA:37,0
+DA:40,0
+DA:44,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:66,0
+DA:71,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:84,0
+DA:87,0
+DA:88,0
+DA:89,0
+DA:90,0
+DA:123,0
+DA:124,0
+DA:125,0
+DA:141,0
+DA:142,0
+DA:145,0
+DA:147,0
+DA:155,0
+DA:159,0
+DA:160,0
+DA:162,0
+DA:163,0
+DA:166,0
+DA:167,0
+DA:170,0
+DA:171,0
+DA:175,0
+DA:176,0
+DA:177,0
+DA:178,0
+DA:179,0
+DA:180,0
+DA:184,0
+DA:190,0
+DA:192,0
+DA:193,0
+DA:195,0
+DA:196,0
+DA:200,0
+DA:207,0
+DA:208,0
+DA:210,0
+DA:213,0
+DA:215,0
+DA:216,0
+DA:217,0
+DA:218,0
+DA:221,0
+DA:222,0
+DA:223,0
+DA:226,0
+DA:227,0
+DA:228,0
+DA:229,0
+DA:230,0
+DA:232,0
+DA:233,0
+DA:234,0
+DA:239,0
+DA:240,0
+DA:241,0
+DA:245,0
+DA:247,0
+DA:248,0
+DA:249,0
+DA:250,0
+DA:251,0
+DA:252,0
+DA:254,0
+DA:255,0
+DA:256,0
+DA:259,0
+DA:260,0
+DA:263,0
+DA:264,0
+DA:265,0
+DA:267,0
+DA:270,0
+DA:273,0
+DA:274,0
+DA:275,0
+DA:278,0
+DA:279,0
+DA:282,0
+DA:285,0
+DA:287,0
+DA:288,0
+DA:290,0
+DA:291,0
+DA:314,0
+DA:315,0
+DA:316,0
+DA:317,0
+DA:320,0
+DA:322,0
+DA:326,0
+DA:328,0
+DA:329,0
+DA:330,0
+DA:331,0
+DA:334,0
+DA:335,0
+DA:336,0
+DA:341,0
+DA:342,0
+DA:343,0
+DA:345,0
+DA:348,0
+DA:350,0
+DA:351,0
+DA:352,0
+DA:355,0
+DA:356,0
+DA:357,0
+DA:358,0
+DA:359,0
+DA:360,0
+DA:363,0
+DA:364,0
+DA:365,0
+DA:371,0
+DA:372,0
+DA:373,0
+DA:374,0
+DA:375,0
+DA:376,0
+DA:379,0
+DA:380,0
+DA:381,0
+DA:382,0
+DA:383,0
+DA:384,0
+DA:385,0
+DA:386,0
+DA:388,0
+DA:391,0
+DA:392,0
+DA:393,0
+DA:394,0
+DA:399,0
+DA:400,0
+DA:401,0
+DA:404,0
+DA:405,0
+DA:406,0
+DA:409,0
+DA:410,0
+DA:411,0
+DA:412,0
+DA:413,0
+DA:414,0
+DA:415,0
+DA:417,0
+DA:418,0
+DA:422,0
+DA:423,0
+DA:424,0
+DA:425,0
+DA:426,0
+DA:427,0
+DA:429,0
+DA:430,0
+DA:434,0
+DA:435,0
+DA:437,0
+DA:440,0
+DA:441,0
+DA:443,0
+DA:444,0
+DA:445,0
+DA:446,0
+DA:447,0
+DA:448,0
+DA:453,0
+DA:454,0
+DA:455,0
+DA:456,0
+DA:457,0
+DA:458,0
+DA:459,0
+DA:461,0
+DA:465,0
+DA:466,0
+DA:467,0
+DA:468,0
+DA:474,0
+DA:475,0
+DA:477,0
+DA:482,0
+DA:483,0
+DA:484,0
+DA:488,0
+DA:490,0
+DA:492,0
+DA:493,0
+DA:495,0
+DA:497,0
+DA:499,0
+DA:501,0
+DA:502,0
+DA:504,0
+DA:506,0
+DA:508,0
+DA:510,0
+DA:511,0
+DA:513,0
+DA:515,0
+DA:517,0
+DA:518,0
+DA:519,0
+DA:520,0
+DA:521,0
+DA:522,0
+DA:524,0
+DA:526,0
+DA:528,0
+DA:529,0
+DA:530,0
+DA:531,0
+DA:532,0
+DA:533,0
+DA:535,0
+DA:537,0
+DA:539,0
+DA:540,0
+DA:541,0
+DA:545,0
+DA:547,0
+DA:548,0
+DA:549,0
+DA:553,0
+DA:555,0
+DA:556,0
+DA:557,0
+DA:561,0
+DA:566,0
+DA:568,0
+DA:569,0
+DA:571,0
+DA:573,0
+DA:575,0
+DA:576,0
+DA:577,0
+DA:578,0
+DA:581,0
+DA:595,0
+DA:596,0
+DA:597,0
+DA:598,0
+DA:599,0
+DA:600,0
+DA:601,0
+DA:602,0
+DA:603,0
+DA:604,0
+DA:605,0
+DA:609,0
+DA:610,0
+DA:611,0
+DA:612,0
+DA:625,0
+DA:626,0
+DA:627,0
+DA:628,0
+DA:629,0
+DA:630,0
+DA:631,0
+DA:632,0
+DA:633,0
+DA:634,0
+DA:635,0
+DA:637,0
+DA:638,0
+DA:639,0
+DA:640,0
+DA:641,0
+DA:642,0
+DA:643,0
+DA:644,0
+DA:645,0
+DA:647,0
+DA:649,0
+DA:651,0
+DA:653,0
+DA:655,0
+DA:657,0
+DA:659,0
+DA:661,0
+DA:663,0
+DA:665,0
+DA:667,0
+DA:669,0
+DA:671,0
+DA:673,0
+DA:675,0
+DA:677,0
+DA:679,0
+DA:681,0
+DA:682,0
+DA:683,0
+DA:685,0
+DA:687,0
+DA:688,0
+DA:689,0
+DA:690,0
+DA:691,0
+DA:693,0
+DA:694,0
+DA:695,0
+DA:696,0
+DA:697,0
+DA:699,0
+DA:701,0
+DA:703,0
+DA:705,0
+DA:707,0
+DA:709,0
+DA:711,0
+DA:713,0
+DA:715,0
+DA:716,0
+DA:717,0
+DA:719,0
+DA:720,0
+DA:721,0
+DA:722,0
+DA:723,0
+DA:725,0
+LF:334
+LH:0
+end_of_record
+SF:lib\views\feedback_view\feedback_view.dart
+DA:17,0
+DA:20,17
+DA:22,0
+DA:23,0
+DA:32,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:40,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:53,0
+DA:55,0
+DA:56,0
+DA:59,0
+DA:60,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:68,0
+DA:70,0
+DA:71,0
+DA:73,0
+DA:74,0
+DA:75,0
+DA:76,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:87,0
+DA:92,0
+DA:94,0
+DA:95,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:100,0
+DA:101,0
+DA:102,0
+DA:103,0
+DA:104,0
+DA:106,0
+DA:114,0
+DA:116,0
+DA:117,0
+DA:118,0
+DA:119,0
+DA:122,0
+DA:123,0
+DA:125,0
+DA:126,0
+DA:128,0
+DA:132,0
+DA:135,0
+DA:136,0
+DA:137,0
+DA:139,0
+DA:140,0
+DA:148,0
+DA:149,0
+DA:151,0
+DA:152,0
+DA:154,0
+DA:156,0
+DA:158,0
+DA:159,0
+DA:160,0
+DA:161,0
+DA:163,0
+DA:164,0
+DA:165,0
+DA:166,0
+DA:173,0
+DA:175,0
+DA:176,0
+DA:190,0
+DA:191,0
+LF:84
+LH:1
+end_of_record
+SF:lib\model\encryption\aes_encrypted.dart
+DA:8,0
+DA:23,0
+DA:32,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:54,0
+DA:60,0
+DA:69,0
+DA:70,0
+DA:72,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:82,0
+DA:83,0
+DA:84,0
+DA:87,0
+DA:88,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:102,0
+DA:106,0
+DA:108,0
+DA:109,0
+DA:110,0
+DA:111,0
+DA:112,0
+DA:113,0
+DA:117,0
+LF:45
+LH:0
+end_of_record
+SF:lib\model\encryption\token_encryption.dart
+DA:9,0
+DA:10,0
+DA:11,0
+DA:12,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+LF:20
+LH:0
+end_of_record
+SF:lib\processors\scheme_processors\token_import_scheme_processors\privacyidea_authenticator_qr_processor.dart
+DA:10,34
+DA:14,0
+DA:15,0
+DA:17,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:26,0
+DA:28,0
+DA:30,0
+LF:11
+LH:1
+end_of_record
+SF:lib\model\encryption\uint_8_buffer.dart
+DA:6,0
+DA:7,0
+DA:8,0
+DA:12,0
+DA:13,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:34,0
+LF:12
+LH:0
+end_of_record
+SF:lib\model\enums\algorithms.dart
+DA:15,2
+DA:23,6
+DA:24,2
+DA:25,6
+DA:26,2
+DA:27,6
+DA:28,2
+DA:31,3
+DA:38,6
+DA:39,3
+DA:40,3
+DA:41,3
+DA:42,3
+DA:45,0
+DA:46,0
+DA:49,4
+DA:50,4
+DA:51,2
+DA:52,1
+DA:53,1
+DA:54,0
+DA:55,1
+DA:66,1
+DA:73,1
+DA:75,0
+DA:81,1
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:99,0
+DA:100,0
+DA:107,1
+DA:109,0
+DA:110,0
+LF:39
+LH:23
+end_of_record
+SF:lib\model\extensions\enum_extension.dart
+DA:2,28
+DA:4,0
+DA:5,0
+DA:6,0
+DA:10,0
+DA:13,5
+LF:6
+LH:2
+end_of_record
+SF:lib\model\enums\encodings.dart
+DA:14,5
+DA:15,6
+DA:16,10
+DA:17,2
+DA:20,0
+DA:22,2
+DA:23,3
+DA:24,6
+DA:25,3
+DA:28,1
+DA:30,1
+DA:37,0
+DA:39,0
+DA:46,1
+DA:48,1
+DA:54,0
+DA:56,0
+DA:62,0
+DA:63,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:75,0
+DA:76,0
+DA:77,0
+LF:29
+LH:12
+end_of_record
+SF:lib\model\enums\patch_note_type.dart
+DA:10,0
+DA:11,0
+DA:12,0
+DA:13,0
+LF:4
+LH:0
+end_of_record
+SF:lib\model\enums\push_token_rollout_state.dart
+DA:17,1
+DA:18,1
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+LF:18
+LH:2
+end_of_record
+SF:lib\model\enums\token_import_type.dart
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+LF:11
+LH:0
+end_of_record
+SF:lib\model\enums\token_origin_source_type.dart
+DA:17,2
+DA:20,0
+DA:22,1
+DA:25,1
+DA:26,2
+LF:5
+LH:4
+end_of_record
+SF:lib\model\token_import\token_origin_data.dart
+DA:16,1
+DA:25,1
+DA:33,1
+DA:38,0
+DA:42,0
+DA:45,0
+DA:48,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:62,0
+DA:65,0
+DA:66,0
+DA:69,0
+DA:70,0
+DA:72,0
+DA:74,0
+LF:20
+LH:3
+end_of_record
+SF:lib\model\token_import\token_origin_data.g.dart
+DA:9,0
+DA:10,0
+DA:11,0
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:17,0
+DA:18,0
+DA:20,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+LF:18
+LH:0
+end_of_record
+SF:lib\model\extensions\color_extension.dart
+DA:4,0
+DA:5,0
+DA:6,0
+DA:7,0
+DA:8,0
+DA:9,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+LF:12
+LH:0
+end_of_record
+SF:lib\model\extensions\int_extension.dart
+DA:5,0
+DA:7,0
+DA:9,0
+DA:10,0
+DA:11,0
+DA:12,0
+DA:17,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:25,0
+LF:11
+LH:0
+end_of_record
+SF:lib\model\processor_result.dart
+DA:2,0
+DA:3,0
+DA:4,0
+DA:9,1
+DA:11,0
+DA:13,0
+DA:19,17
+DA:21,0
+DA:23,0
+LF:9
+LH:2
+end_of_record
+SF:lib\utils\identifiers.dart
+DA:69,0
+DA:70,0
+DA:71,0
+LF:3
+LH:0
+end_of_record
+SF:lib\utils\rsa_utils.dart
+DA:38,87
+DA:47,2
+DA:48,6
+DA:49,6
+DA:50,6
+DA:52,2
+DA:62,2
+DA:63,2
+DA:64,6
+DA:65,6
+DA:67,4
+DA:82,1
+DA:83,3
+DA:85,2
+DA:87,3
+DA:89,2
+DA:90,0
+DA:91,0
+DA:97,2
+DA:99,3
+DA:101,3
+DA:102,3
+DA:104,1
+DA:119,1
+DA:120,1
+DA:121,1
+DA:122,2
+DA:123,2
+DA:125,1
+DA:126,3
+DA:127,3
+DA:129,2
+DA:131,1
+DA:132,1
+DA:133,1
+DA:134,2
+DA:155,2
+DA:156,2
+DA:157,4
+DA:158,6
+DA:159,6
+DA:160,6
+DA:161,6
+DA:162,6
+DA:163,14
+DA:164,14
+DA:165,10
+DA:167,4
+DA:188,2
+DA:189,6
+DA:190,6
+DA:191,6
+DA:192,6
+DA:193,6
+DA:195,2
+DA:199,1
+DA:200,1
+DA:201,2
+DA:205,2
+DA:206,0
+DA:207,0
+DA:219,0
+DA:220,0
+DA:221,0
+DA:225,0
+DA:227,0
+DA:228,0
+DA:229,0
+DA:235,2
+DA:236,2
+DA:237,4
+DA:238,2
+DA:243,2
+DA:244,12
+DA:246,2
+DA:248,6
+DA:251,0
+DA:252,0
+DA:255,1
+DA:256,1
+DA:257,2
+DA:259,2
+LF:82
+LH:69
+end_of_record
+SF:lib\model\tokens\push_token.dart
+DA:18,2
+DA:23,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,4
+DA:43,0
+DA:44,4
+DA:46,3
+DA:72,6
+DA:74,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:86,0
+DA:88,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:96,2
+DA:121,2
+DA:122,2
+DA:123,2
+DA:124,2
+DA:125,2
+DA:126,2
+DA:127,2
+DA:128,2
+DA:129,2
+DA:130,2
+DA:131,2
+DA:132,2
+DA:133,2
+DA:134,2
+DA:135,2
+DA:136,2
+DA:137,2
+DA:138,2
+DA:139,2
+DA:140,1
+DA:141,3
+DA:142,2
+DA:146,1
+DA:147,7
+DA:149,0
+DA:150,0
+DA:152,0
+DA:154,0
+DA:155,0
+DA:156,0
+DA:157,0
+DA:158,0
+DA:159,0
+DA:160,0
+DA:161,0
+DA:162,0
+DA:163,0
+DA:166,4
+DA:167,2
+DA:168,2
+DA:169,2
+DA:170,2
+DA:171,2
+DA:172,10
+DA:173,2
+DA:174,2
+DA:175,2
+DA:176,2
+DA:177,2
+DA:178,2
+DA:181,1
+DA:182,1
+DA:183,1
+DA:184,1
+DA:185,1
+DA:186,0
+DA:187,0
+DA:188,0
+DA:190,1
+DA:193,1
+DA:194,1
+LF:88
+LH:51
+end_of_record
+SF:lib\model\tokens\push_token.g.dart
+DA:9,2
+DA:10,1
+DA:11,1
+DA:12,1
+DA:13,1
+DA:14,1
+DA:15,3
+DA:16,1
+DA:18,2
+DA:19,1
+DA:20,1
+DA:21,1
+DA:22,1
+DA:23,1
+DA:24,1
+DA:25,1
+DA:26,1
+DA:27,1
+DA:28,1
+DA:29,1
+DA:30,1
+DA:31,1
+DA:32,1
+DA:33,1
+DA:34,1
+DA:36,0
+DA:39,2
+DA:40,1
+DA:41,1
+DA:42,1
+DA:43,1
+DA:44,1
+DA:45,1
+DA:46,1
+DA:47,1
+DA:48,1
+DA:49,1
+DA:50,1
+DA:51,2
+DA:52,1
+DA:53,1
+DA:54,1
+DA:55,1
+DA:56,2
+DA:57,1
+DA:58,2
+DA:59,1
+DA:60,1
+DA:61,1
+LF:49
+LH:48
+end_of_record
+SF:lib\utils\custom_int_buffer.dart
+DA:10,37
+DA:12,1
+DA:13,1
+DA:14,1
+DA:15,1
+DA:19,3
+DA:20,1
+DA:21,3
+DA:22,4
+DA:23,2
+DA:26,1
+DA:27,3
+DA:28,3
+DA:29,0
+DA:31,2
+DA:34,3
+DA:35,0
+DA:36,0
+DA:37,6
+DA:39,1
+DA:42,4
+DA:45,0
+DA:46,0
+DA:48,0
+DA:49,0
+LF:25
+LH:18
+end_of_record
+SF:lib\utils\custom_int_buffer.g.dart
+DA:9,0
+DA:10,0
+DA:11,0
+DA:14,0
+DA:15,0
+DA:16,0
+LF:6
+LH:0
+end_of_record
+SF:lib\utils\version.dart
+DA:11,19
+DA:16,2
+DA:17,2
+DA:18,4
+DA:19,0
+DA:21,14
+DA:24,0
+DA:26,0
+DA:27,0
+DA:30,0
+DA:31,0
+DA:34,0
+DA:35,0
+DA:38,0
+DA:39,0
+DA:42,0
+DA:43,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:52,0
+DA:55,0
+DA:56,0
+DA:59,0
+DA:60,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:70,0
+DA:74,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:82,0
+DA:84,0
+DA:85,0
+DA:86,0
+DA:89,0
+DA:90,0
+DA:92,0
+DA:94,0
+DA:96,0
+DA:97,0
+LF:45
+LH:5
+end_of_record
+SF:lib\utils\version.g.dart
+DA:9,0
+DA:10,0
+DA:11,0
+DA:12,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+LF:8
+LH:0
+end_of_record
+SF:lib\model\states\token_filter.dart
+DA:6,0
+DA:7,0
+DA:8,0
+DA:11,0
+DA:13,0
+DA:15,0
+DA:16,0
+DA:17,0
+LF:8
+LH:0
+end_of_record
+SF:lib\model\states\token_folder_state.dart
+DA:12,20
+DA:14,2
+DA:15,4
+DA:16,6
+DA:17,2
+DA:22,2
+DA:23,4
+DA:24,4
+DA:25,10
+DA:26,4
+DA:27,2
+DA:30,2
+DA:33,2
+DA:34,4
+DA:35,10
+DA:36,2
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:45,0
+DA:47,0
+DA:49,0
+DA:50,0
+DA:52,0
+DA:53,0
+DA:55,10
+DA:57,0
+LF:28
+LH:17
+end_of_record
+SF:lib\model\states\token_state.dart
+DA:16,4
+DA:17,3
+DA:19,4
+DA:20,0
+DA:21,5
+DA:23,1
+DA:24,7
+DA:26,2
+DA:27,2
+DA:28,2
+DA:29,4
+DA:32,0
+DA:34,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:44,0
+DA:45,0
+DA:64,2
+DA:65,10
+DA:68,7
+DA:69,0
+DA:71,1
+DA:72,2
+DA:73,1
+DA:74,2
+DA:77,1
+DA:78,2
+DA:79,1
+DA:80,1
+DA:85,2
+DA:86,4
+DA:87,10
+DA:88,2
+DA:91,1
+DA:92,2
+DA:93,7
+DA:94,1
+DA:99,2
+DA:100,4
+DA:101,10
+DA:102,4
+DA:103,2
+DA:105,2
+DA:107,4
+DA:112,1
+DA:113,2
+DA:114,5
+DA:115,2
+DA:116,0
+DA:119,1
+DA:120,2
+DA:125,2
+DA:126,4
+DA:127,2
+DA:128,4
+DA:129,10
+DA:130,4
+DA:131,2
+DA:132,2
+DA:135,2
+DA:136,2
+DA:138,2
+DA:143,1
+DA:144,2
+DA:145,1
+DA:146,1
+DA:147,1
+DA:148,0
+DA:149,0
+DA:150,0
+DA:151,0
+DA:154,0
+DA:156,1
+DA:159,0
+DA:160,0
+DA:163,0
+DA:164,0
+DA:166,0
+DA:168,0
+DA:169,0
+DA:172,0
+DA:173,0
+DA:175,0
+LF:84
+LH:59
+end_of_record
+SF:lib\model\tokens\otp_token.dart
+DA:11,0
+DA:13,0
+DA:17,4
+DA:38,0
+DA:40,0
+DA:60,0
+DA:62,0
+LF:7
+LH:1
+end_of_record
+SF:lib\model\token_import\token_import_origin.dart
+DA:11,0
+DA:23,0
+LF:2
+LH:0
+end_of_record
+SF:lib\processors\mixins\token_import_processor.dart
+DA:7,0
+DA:8,0
+DA:9,0
+LF:3
+LH:0
+end_of_record
+SF:lib\model\tokens\day_password_token.dart
+DA:20,0
+DA:24,1
+DA:41,2
+DA:42,2
+DA:44,0
+DA:47,0
+DA:50,0
+DA:53,0
+DA:56,0
+DA:58,0
+DA:61,0
+DA:62,0
+DA:64,0
+DA:82,0
+DA:83,0
+DA:84,0
+DA:85,0
+DA:86,0
+DA:87,0
+DA:88,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:101,1
+DA:102,2
+DA:103,1
+DA:104,1
+DA:105,1
+DA:106,1
+DA:110,0
+DA:111,0
+DA:112,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:119,0
+DA:122,0
+DA:123,0
+DA:124,0
+DA:125,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:130,0
+DA:131,0
+DA:132,0
+DA:133,0
+DA:134,0
+DA:135,0
+DA:136,0
+DA:137,0
+DA:138,0
+DA:142,0
+DA:143,0
+DA:144,0
+DA:146,0
+DA:147,0
+LF:64
+LH:9
+end_of_record
+SF:lib\model\tokens\day_password_token.g.dart
+DA:9,0
+DA:10,0
+DA:11,0
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:50,0
+LF:38
+LH:0
+end_of_record
+SF:lib\model\tokens\hotp_token.dart
+DA:17,0
+DA:20,0
+DA:23,4
+DA:39,8
+DA:41,0
+DA:42,0
+DA:44,0
+DA:46,0
+DA:48,3
+DA:49,6
+DA:50,3
+DA:51,3
+DA:52,3
+DA:56,4
+DA:58,2
+DA:75,2
+DA:76,1
+DA:77,2
+DA:78,2
+DA:79,1
+DA:80,2
+DA:81,2
+DA:82,2
+DA:83,2
+DA:84,2
+DA:85,2
+DA:86,2
+DA:87,2
+DA:88,3
+DA:89,2
+DA:92,0
+DA:94,0
+DA:97,1
+DA:98,2
+DA:99,3
+DA:100,1
+DA:101,1
+DA:102,1
+DA:103,1
+DA:104,2
+DA:105,1
+DA:106,2
+DA:107,1
+DA:108,1
+DA:109,1
+DA:110,1
+DA:111,1
+DA:115,0
+DA:116,0
+DA:117,0
+LF:50
+LH:39
+end_of_record
+SF:lib\model\tokens\hotp_token.g.dart
+DA:9,0
+DA:10,0
+DA:11,0
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:44,0
+LF:33
+LH:0
+end_of_record
+SF:lib\model\tokens\steam_token.dart
+DA:20,0
+DA:22,0
+DA:25,0
+DA:39,0
+DA:40,0
+DA:44,0
+DA:61,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:82,0
+DA:83,0
+DA:85,0
+DA:87,0
+DA:88,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:93,0
+DA:95,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:100,0
+DA:103,0
+DA:104,0
+DA:105,0
+DA:106,0
+DA:107,0
+DA:108,0
+DA:109,0
+DA:110,0
+DA:111,0
+DA:112,0
+DA:114,0
+DA:115,0
+DA:116,0
+LF:47
+LH:0
+end_of_record
+SF:lib\model\tokens\steam_token.g.dart
+DA:9,0
+DA:10,0
+DA:11,0
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+LF:30
+LH:0
+end_of_record
+SF:lib\model\tokens\totp_token.dart
+DA:18,4
+DA:23,0
+DA:25,0
+DA:26,0
+DA:32,1
+DA:33,2
+DA:34,1
+DA:35,1
+DA:36,1
+DA:37,2
+DA:41,2
+DA:57,2
+DA:58,4
+DA:64,0
+DA:65,0
+DA:67,2
+DA:84,2
+DA:85,1
+DA:86,1
+DA:87,1
+DA:88,1
+DA:89,1
+DA:90,1
+DA:91,1
+DA:92,1
+DA:93,1
+DA:94,1
+DA:95,1
+DA:96,2
+DA:97,2
+DA:98,1
+DA:102,0
+DA:104,0
+DA:107,2
+DA:108,3
+DA:109,7
+DA:110,7
+DA:111,2
+DA:112,2
+DA:113,2
+DA:114,2
+DA:115,4
+DA:116,2
+DA:117,2
+DA:118,4
+DA:119,2
+DA:120,2
+DA:121,2
+DA:122,2
+DA:126,0
+DA:127,0
+DA:128,0
+DA:131,0
+DA:132,0
+DA:133,0
+DA:136,1
+DA:137,1
+DA:138,2
+LF:58
+LH:45
+end_of_record
+SF:lib\model\tokens\totp_token.g.dart
+DA:9,2
+DA:10,1
+DA:11,1
+DA:12,2
+DA:13,1
+DA:14,1
+DA:15,1
+DA:16,1
+DA:17,1
+DA:18,1
+DA:19,1
+DA:20,1
+DA:21,1
+DA:22,1
+DA:24,0
+DA:25,1
+DA:26,1
+DA:29,2
+DA:30,1
+DA:31,1
+DA:32,1
+DA:33,1
+DA:34,1
+DA:35,1
+DA:36,1
+DA:37,1
+DA:38,1
+DA:39,1
+DA:40,1
+DA:41,2
+DA:42,1
+DA:43,1
+DA:44,1
+LF:33
+LH:32
+end_of_record
+SF:lib\processors\scheme_processors\token_import_scheme_processors\google_authenticator_qr_processor.dart
+DA:19,51
+DA:22,0
+DA:23,0
+DA:24,0
+DA:26,0
+DA:27,0
+DA:30,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:37,0
+DA:38,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:48,0
+DA:49,0
+DA:52,0
+DA:55,0
+DA:58,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:71,0
+DA:82,0
+DA:83,0
+DA:84,0
+DA:88,0
+DA:90,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:100,0
+DA:101,0
+DA:104,0
+DA:106,0
+DA:111,0
+DA:112,0
+DA:113,0
+DA:114,0
+DA:115,0
+DA:116,0
+DA:118,0
+DA:121,0
+LF:48
+LH:1
+end_of_record
+SF:lib\processors\token_import_file_processor\token_import_file_processor_interface.dart
+DA:11,34
+DA:13,0
+DA:15,0
+DA:20,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:29,0
+DA:32,0
+DA:36,0
+LF:10
+LH:1
+end_of_record
+SF:lib\processors\scheme_processors\home_widget_processor.dart
+DA:6,51
+DA:8,0
+DA:14,0
+DA:16,0
+DA:17,0
+DA:20,0
+DA:21,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:28,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:36,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:44,0
+LF:22
+LH:1
+end_of_record
+SF:lib\processors\scheme_processors\scheme_processor_interface.dart
+DA:6,0
+DA:10,0
+DA:12,0
+DA:13,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+LF:8
+LH:0
+end_of_record
+SF:lib\processors\scheme_processors\navigation_scheme_processors\home_widget_navigate_processor.dart
+DA:11,0
+DA:13,0
+DA:18,0
+DA:21,0
+DA:23,0
+DA:24,0
+DA:28,0
+DA:29,0
+DA:32,0
+DA:33,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:40,0
+DA:41,0
+DA:45,0
+DA:46,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:52,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:63,0
+DA:64,0
+DA:67,0
+DA:68,0
+DA:70,0
+DA:72,0
+DA:75,0
+DA:77,0
+DA:80,0
+DA:82,0
+DA:83,0
+DA:85,0
+LF:36
+LH:0
+end_of_record
+SF:lib\views\link_home_widget_view\link_home_widget_view.dart
+DA:12,0
+DA:19,0
+DA:21,0
+DA:22,0
+DA:27,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:55,0
+LF:27
+LH:0
+end_of_record
+SF:lib\processors\scheme_processors\navigation_scheme_processors\navigation_scheme_processor_interface.dart
+DA:9,0
+DA:11,0
+DA:12,0
+DA:18,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:32,0
+DA:35,0
+LF:15
+LH:0
+end_of_record
+SF:lib\processors\scheme_processors\token_import_scheme_processors\token_import_scheme_processor_interface.dart
+DA:10,119
+DA:17,0
+DA:21,0
+DA:26,1
+DA:27,2
+DA:28,3
+DA:29,1
+LF:7
+LH:5
+end_of_record
+SF:lib\processors\scheme_processors\token_import_scheme_processors\free_otp_plus_qr_processor.dart
+DA:10,34
+DA:12,0
+DA:13,0
+DA:15,0
+DA:16,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:22,0
+DA:23,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:32,0
+DA:35,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:47,0
+DA:54,0
+DA:55,0
+LF:27
+LH:1
+end_of_record
+SF:lib\utils\token_import_origins.dart
+DA:16,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:27,0
+DA:28,0
+DA:30,0
+DA:31,0
+DA:34,0
+DA:36,0
+DA:39,0
+DA:43,0
+DA:46,0
+DA:47,0
+DA:50,0
+DA:52,0
+DA:55,0
+DA:59,0
+DA:62,0
+DA:63,0
+DA:66,0
+DA:68,0
+DA:71,0
+DA:73,0
+DA:76,0
+DA:80,0
+DA:83,0
+DA:84,0
+DA:87,0
+DA:91,0
+DA:94,0
+DA:95,0
+DA:98,0
+DA:102,0
+DA:105,0
+DA:106,0
+DA:109,0
+DA:111,0
+DA:114,0
+LF:42
+LH:0
+end_of_record
+SF:lib\processors\scheme_processors\token_import_scheme_processors\otp_auth_processor.dart
+DA:20,102
+DA:21,1
+DA:22,1
+DA:24,1
+DA:26,3
+DA:27,1
+DA:30,1
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:36,1
+DA:37,0
+DA:38,0
+DA:42,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:51,0
+DA:53,0
+DA:57,1
+DA:58,0
+DA:59,0
+DA:60,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:66,2
+DA:72,1
+DA:73,1
+DA:74,1
+DA:76,1
+DA:78,3
+DA:79,1
+DA:81,0
+DA:82,0
+DA:84,0
+DA:88,1
+DA:90,1
+DA:93,2
+DA:97,3
+DA:98,3
+DA:101,3
+DA:103,1
+DA:108,1
+DA:109,1
+DA:110,1
+DA:113,3
+DA:114,0
+DA:117,2
+DA:118,0
+DA:121,2
+DA:122,2
+DA:124,1
+DA:127,2
+DA:129,1
+DA:130,0
+DA:133,0
+DA:137,1
+DA:139,1
+DA:142,2
+DA:143,1
+DA:149,3
+DA:150,1
+DA:152,1
+DA:153,1
+DA:155,0
+DA:158,0
+DA:162,1
+DA:164,2
+DA:166,0
+DA:169,0
+DA:175,0
+DA:176,0
+DA:177,0
+DA:180,0
+DA:185,2
+DA:187,2
+DA:189,1
+DA:191,0
+DA:193,1
+DA:196,1
+DA:198,0
+DA:199,0
+DA:200,0
+DA:204,0
+DA:205,0
+DA:206,0
+DA:209,0
+DA:213,0
+DA:214,0
+DA:215,0
+DA:218,0
+DA:222,0
+DA:223,0
+DA:224,0
+DA:227,0
+DA:235,1
+DA:245,1
+DA:247,2
+DA:250,2
+DA:253,0
+DA:257,1
+DA:259,2
+DA:261,1
+DA:262,0
+DA:263,0
+DA:265,0
+DA:268,0
+DA:269,0
+DA:270,0
+DA:272,0
+DA:276,2
+DA:277,0
+DA:280,1
+DA:281,1
+DA:282,1
+DA:283,3
+DA:284,2
+DA:286,2
+DA:287,1
+DA:289,2
+DA:290,0
+DA:291,0
+DA:294,2
+DA:296,2
+DA:297,0
+DA:298,0
+DA:301,3
+DA:302,2
+DA:304,4
+DA:307,3
+DA:308,0
+DA:315,1
+DA:318,2
+DA:319,1
+DA:322,1
+DA:323,1
+DA:324,1
+DA:325,1
+DA:327,1
+DA:330,0
+DA:337,1
+DA:339,2
+DA:342,1
+DA:343,0
+DA:350,1
+DA:351,6
+LF:149
+LH:83
+end_of_record
+SF:lib\proto\generated\GoogleAuthenticatorImport.pb.dart
+DA:23,0
+DA:32,0
+DA:34,0
+DA:37,0
+DA:40,0
+DA:43,0
+DA:46,0
+DA:49,0
+DA:52,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:62,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:71,0
+DA:75,0
+DA:79,0
+DA:80,0
+DA:82,0
+DA:85,0
+DA:86,0
+DA:90,0
+DA:92,0
+DA:94,0
+DA:95,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:100,0
+DA:103,0
+DA:104,0
+DA:105,0
+DA:107,0
+DA:110,0
+DA:111,0
+DA:112,0
+DA:113,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:119,0
+DA:122,0
+DA:123,0
+DA:124,0
+DA:125,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:131,0
+DA:134,0
+DA:135,0
+DA:136,0
+DA:137,0
+DA:139,0
+DA:140,0
+DA:141,0
+DA:143,0
+DA:146,0
+DA:147,0
+DA:148,0
+DA:149,0
+DA:151,0
+DA:152,0
+DA:153,0
+DA:155,0
+DA:158,0
+DA:159,0
+DA:160,0
+DA:161,0
+DA:163,0
+DA:164,0
+DA:165,0
+DA:167,0
+DA:170,0
+DA:171,0
+DA:172,0
+DA:173,0
+DA:175,0
+DA:176,0
+DA:177,0
+DA:179,0
+DA:182,0
+DA:183,0
+DA:184,0
+DA:185,0
+DA:189,0
+DA:196,0
+DA:198,0
+DA:201,0
+DA:204,0
+DA:207,0
+DA:210,0
+DA:214,0
+DA:215,0
+DA:216,0
+DA:217,0
+DA:219,0
+DA:221,0
+DA:223,0
+DA:224,0
+DA:225,0
+DA:226,0
+DA:227,0
+DA:229,0
+DA:232,0
+DA:233,0
+DA:237,0
+DA:239,0
+DA:241,0
+DA:242,0
+DA:243,0
+DA:244,0
+DA:245,0
+DA:246,0
+DA:249,0
+DA:250,0
+DA:252,0
+DA:253,0
+DA:254,0
+DA:256,0
+DA:259,0
+DA:260,0
+DA:261,0
+DA:262,0
+DA:264,0
+DA:265,0
+DA:266,0
+DA:268,0
+DA:271,0
+DA:272,0
+DA:273,0
+DA:274,0
+DA:276,0
+DA:277,0
+DA:278,0
+DA:280,0
+DA:283,0
+DA:284,0
+DA:285,0
+DA:286,0
+DA:288,0
+DA:289,0
+DA:290,0
+DA:292,0
+DA:295,0
+DA:296,0
+DA:297,0
+DA:298,0
+LF:153
+LH:0
+end_of_record
+SF:lib\utils\view_utils.dart
+DA:7,0
+DA:11,0
+DA:12,0
+DA:15,0
+DA:16,0
+DA:20,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:28,0
+DA:29,0
+LF:11
+LH:0
+end_of_record
+SF:lib\widgets\dialog_widgets\two_step_dialog.dart
+DA:40,0
+DA:46,0
+DA:48,0
+DA:51,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:65,0
+DA:66,0
+DA:68,0
+DA:73,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:80,0
+DA:81,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:102,0
+DA:104,0
+DA:105,0
+DA:106,0
+DA:109,0
+DA:111,0
+DA:112,0
+DA:116,0
+DA:117,0
+DA:120,0
+DA:121,0
+DA:122,0
+DA:123,0
+DA:124,0
+LF:37
+LH:0
+end_of_record
+SF:lib\processors\token_import_file_processor\aegis_import_file_processor.dart
+DA:26,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:37,0
+DA:41,34
+DA:53,0
+DA:55,0
+DA:61,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:73,0
+DA:77,0
+DA:78,0
+DA:82,0
+DA:85,0
+DA:89,0
+DA:90,0
+DA:94,0
+DA:97,0
+DA:99,0
+DA:102,0
+DA:104,0
+DA:106,0
+DA:107,0
+DA:108,0
+DA:109,0
+DA:111,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:118,0
+DA:120,0
+DA:122,0
+DA:124,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:130,0
+DA:131,0
+DA:132,0
+DA:133,0
+DA:134,0
+DA:135,0
+DA:136,0
+DA:137,0
+DA:138,0
+DA:139,0
+DA:141,0
+DA:144,0
+DA:145,0
+DA:146,0
+DA:148,0
+DA:149,0
+DA:155,0
+DA:156,0
+DA:158,0
+DA:160,0
+DA:162,0
+DA:166,0
+DA:167,0
+DA:168,0
+DA:169,0
+DA:170,0
+DA:171,0
+DA:173,0
+DA:174,0
+DA:177,0
+DA:178,0
+DA:182,0
+DA:183,0
+DA:184,0
+DA:186,0
+DA:188,0
+DA:191,0
+DA:193,0
+DA:194,0
+DA:195,0
+DA:196,0
+DA:197,0
+DA:199,0
+DA:201,0
+DA:202,0
+DA:203,0
+LF:92
+LH:1
+end_of_record
+SF:lib\processors\token_import_file_processor\two_fas_import_file_processor.dart
+DA:22,34
+DA:30,0
+DA:32,0
+DA:35,0
+DA:37,0
+DA:39,0
+DA:40,0
+DA:43,0
+DA:46,0
+DA:47,0
+DA:53,0
+DA:56,0
+DA:57,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:69,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:83,0
+DA:85,0
+DA:89,0
+DA:91,0
+DA:92,0
+DA:95,0
+DA:97,0
+DA:99,0
+DA:102,0
+DA:104,0
+DA:106,0
+DA:108,0
+DA:109,0
+DA:110,0
+DA:111,0
+DA:113,0
+DA:114,0
+DA:117,0
+DA:118,0
+DA:121,0
+DA:122,0
+DA:123,0
+DA:125,0
+DA:126,0
+DA:127,0
+DA:129,0
+DA:130,0
+DA:133,0
+DA:137,0
+DA:138,0
+DA:139,0
+DA:140,0
+DA:141,0
+DA:142,0
+DA:143,0
+DA:144,0
+DA:145,0
+DA:146,0
+DA:147,0
+DA:149,0
+DA:157,0
+DA:158,0
+DA:160,0
+DA:166,0
+DA:167,0
+DA:169,0
+LF:71
+LH:1
+end_of_record
+SF:lib\processors\token_import_file_processor\authenticator_pro_import_file_processor.dart
+DA:45,0
+DA:46,0
+DA:47,0
+DA:49,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:59,17
+DA:61,0
+DA:63,0
+DA:65,0
+DA:67,0
+DA:70,0
+DA:73,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:90,0
+DA:92,0
+DA:94,0
+DA:98,0
+DA:99,0
+DA:100,0
+DA:102,0
+DA:109,0
+DA:111,0
+DA:113,0
+DA:114,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:118,0
+DA:119,0
+DA:120,0
+DA:121,0
+DA:123,0
+DA:125,0
+DA:126,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:131,0
+DA:133,0
+DA:136,0
+DA:145,0
+DA:152,0
+DA:153,0
+DA:154,0
+DA:155,0
+DA:156,0
+DA:161,0
+DA:163,0
+DA:167,0
+DA:175,0
+DA:176,0
+DA:179,0
+DA:181,0
+DA:182,0
+DA:184,0
+DA:186,0
+DA:187,0
+DA:188,0
+DA:192,0
+DA:194,0
+DA:198,0
+DA:200,0
+DA:201,0
+DA:204,0
+DA:205,0
+DA:207,0
+DA:208,0
+DA:212,0
+DA:215,0
+DA:216,0
+DA:217,0
+DA:219,0
+DA:220,0
+DA:221,0
+DA:222,0
+DA:224,0
+DA:225,0
+DA:231,0
+DA:232,0
+DA:233,0
+DA:235,0
+DA:236,0
+DA:237,0
+DA:238,0
+DA:239,0
+DA:240,0
+DA:241,0
+DA:244,0
+DA:245,0
+DA:246,0
+DA:247,0
+DA:249,0
+DA:250,0
+DA:256,0
+DA:257,0
+DA:259,0
+DA:260,0
+DA:265,0
+DA:266,0
+DA:267,0
+DA:268,0
+DA:270,0
+DA:271,0
+DA:273,0
+DA:276,0
+DA:278,0
+DA:279,0
+DA:280,0
+DA:281,0
+DA:282,0
+DA:283,0
+DA:284,0
+DA:285,0
+DA:286,0
+DA:288,0
+DA:292,0
+DA:293,0
+DA:294,0
+DA:295,0
+DA:297,0
+DA:298,0
+LF:127
+LH:1
+end_of_record
+SF:lib\processors\token_import_file_processor\free_otp_plus_file_processor.dart
+DA:32,17
+DA:34,0
+DA:38,0
+DA:43,0
+DA:44,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:56,0
+DA:59,0
+DA:61,0
+DA:63,0
+DA:64,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:71,0
+DA:72,0
+DA:74,0
+DA:75,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:84,0
+DA:86,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:93,0
+DA:95,0
+DA:96,0
+DA:101,0
+DA:103,0
+DA:104,0
+DA:105,0
+DA:107,0
+DA:108,0
+DA:112,0
+DA:113,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:118,0
+DA:119,0
+DA:120,0
+DA:121,0
+DA:122,0
+DA:123,0
+DA:124,0
+DA:126,0
+LF:52
+LH:1
+end_of_record
+SF:lib\processors\token_import_file_processor\privacyidea_authenticator_import_file_processor.dart
+DA:13,17
+DA:14,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:28,0
+DA:29,0
+DA:31,0
+DA:33,0
+DA:36,0
+DA:39,0
+DA:41,0
+DA:43,0
+DA:46,0
+DA:47,0
+LF:15
+LH:1
+end_of_record
+SF:lib\proto\generated\GoogleAuthenticatorImport.pbenum.dart
+DA:31,0
+DA:32,0
+DA:34,17
+DA:48,0
+DA:49,0
+DA:51,17
+DA:65,0
+DA:66,0
+DA:68,17
+LF:9
+LH:3
+end_of_record
+SF:lib\repo\preference_introduction_repository.dart
+DA:12,0
+DA:14,0
+DA:17,0
+DA:18,0
+DA:20,0
+DA:21,0
+DA:24,0
+DA:35,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:42,0
+LF:12
+LH:0
+end_of_record
+SF:lib\repo\preference_settings_repository.dart
+DA:22,0
+DA:23,0
+DA:26,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:41,0
+DA:45,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:62,0
+DA:63,0
+LF:33
+LH:0
+end_of_record
+SF:lib\repo\preference_token_folder_repository.dart
+DA:12,0
+DA:14,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:23,0
+DA:24,0
+DA:28,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:36,0
+LF:14
+LH:0
+end_of_record
+SF:lib\repo\secure_push_request_repository.dart
+DA:14,34
+DA:17,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:36,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:46,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:57,0
+DA:60,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:70,0
+DA:71,0
+DA:75,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:87,0
+DA:92,0
+DA:93,0
+LF:33
+LH:1
+end_of_record
+SF:lib\repo\secure_token_repository.dart
+DA:44,51
+DA:47,0
+DA:51,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:63,0
+DA:66,0
+DA:72,0
+DA:73,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:83,0
+DA:85,0
+DA:86,0
+DA:87,0
+DA:89,0
+DA:96,0
+DA:97,0
+DA:102,0
+DA:103,0
+DA:104,0
+DA:112,0
+DA:114,0
+DA:116,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:130,0
+DA:131,0
+DA:132,0
+DA:135,0
+DA:136,0
+DA:137,0
+DA:139,0
+DA:144,0
+DA:145,0
+DA:147,0
+DA:149,0
+DA:157,0
+DA:158,0
+DA:159,0
+DA:160,0
+DA:161,0
+DA:162,0
+DA:165,0
+DA:166,0
+DA:167,0
+DA:173,0
+DA:174,0
+DA:176,0
+DA:178,0
+DA:180,0
+DA:183,0
+DA:191,0
+DA:193,0
+DA:194,0
+DA:195,0
+DA:196,0
+DA:197,0
+DA:198,0
+DA:199,0
+DA:200,0
+DA:202,0
+DA:203,0
+DA:206,0
+DA:207,0
+DA:208,0
+DA:211,0
+DA:212,0
+DA:213,0
+DA:214,0
+DA:215,0
+DA:217,0
+DA:221,0
+DA:222,0
+DA:223,0
+DA:226,0
+DA:234,0
+DA:238,0
+DA:240,0
+DA:241,0
+DA:243,0
+DA:249,0
+DA:250,0
+DA:251,0
+DA:252,0
+DA:253,0
+DA:254,0
+DA:255,0
+DA:256,0
+DA:258,0
+DA:259,0
+DA:260,0
+DA:265,0
+DA:266,0
+DA:268,0
+DA:269,0
+DA:270,0
+LF:102
+LH:1
+end_of_record
+SF:lib\views\settings_view\settings_view_widgets\send_error_dialog.dart
+DA:11,0
+DA:13,0
+DA:14,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:33,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:43,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:51,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:62,0
+DA:66,0
+DA:68,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:77,0
+DA:78,0
+DA:83,34
+DA:85,0
+DA:87,0
+DA:89,0
+DA:90,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:99,0
+LF:43
+LH:1
+end_of_record
+SF:lib\widgets\dialog_widgets\default_dialog.dart
+DA:14,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:33,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:44,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:52,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:61,0
+DA:62,0
+LF:25
+LH:0
+end_of_record
+SF:lib\widgets\dialog_widgets\default_dialog_button.dart
+DA:7,0
+DA:9,0
+DA:10,0
+LF:3
+LH:0
+end_of_record
+SF:lib\state_notifiers\completed_introduction_notifier.dart
+DA:12,0
+DA:14,0
+DA:15,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:23,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:33,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:40,0
+DA:42,0
+DA:44,0
+DA:46,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:59,0
+DA:60,0
+LF:29
+LH:0
+end_of_record
+SF:lib\state_notifiers\deeplink_notifier.dart
+DA:14,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:21,0
+DA:23,0
+DA:24,0
+DA:26,0
+DA:31,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:46,0
+DA:49,0
+DA:51,0
+DA:52,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:67,0
+LF:24
+LH:0
+end_of_record
+SF:lib\utils\riverpod_state_listener.dart
+DA:14,0
+DA:15,0
+DA:16,0
+DA:21,0
+DA:24,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:38,0
+DA:40,0
+DA:45,0
+DA:47,0
+DA:52,0
+DA:54,0
+DA:59,0
+DA:62,0
+DA:66,0
+DA:68,0
+DA:74,0
+LF:20
+LH:0
+end_of_record
+SF:lib\state_notifiers\push_request_notifier.dart
+DA:48,0
+DA:54,1
+DA:64,1
+DA:67,1
+DA:70,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:76,1
+DA:77,2
+DA:78,3
+DA:79,1
+DA:80,1
+DA:83,0
+DA:85,0
+DA:86,0
+DA:87,0
+DA:97,1
+DA:98,2
+DA:101,2
+DA:103,0
+DA:104,0
+DA:105,0
+DA:107,2
+DA:108,1
+DA:109,2
+DA:115,1
+DA:116,2
+DA:117,1
+DA:118,1
+DA:120,2
+DA:122,0
+DA:123,0
+DA:127,0
+DA:130,1
+DA:131,2
+DA:136,1
+DA:137,2
+DA:138,1
+DA:139,1
+DA:141,0
+DA:145,0
+DA:149,2
+DA:151,0
+DA:152,0
+DA:156,0
+DA:159,1
+DA:160,2
+DA:165,1
+DA:166,2
+DA:167,2
+DA:169,2
+DA:171,0
+DA:176,0
+DA:179,1
+DA:180,1
+DA:181,2
+DA:192,1
+DA:193,2
+DA:194,2
+DA:196,0
+DA:197,0
+DA:200,1
+DA:201,1
+DA:202,2
+DA:213,0
+DA:215,0
+DA:220,1
+DA:221,1
+DA:222,0
+DA:226,1
+DA:227,2
+DA:228,1
+DA:229,1
+DA:235,2
+DA:236,1
+DA:240,1
+DA:241,1
+DA:242,0
+DA:245,1
+DA:246,2
+DA:247,1
+DA:248,1
+DA:254,2
+DA:255,1
+DA:259,1
+DA:260,3
+DA:261,0
+DA:268,1
+DA:270,1
+DA:271,3
+DA:275,2
+DA:281,1
+DA:282,1
+DA:283,1
+DA:286,6
+DA:288,1
+DA:289,3
+DA:290,0
+DA:297,1
+DA:298,4
+DA:299,4
+DA:300,1
+DA:301,0
+DA:304,6
+DA:307,1
+DA:308,1
+DA:309,2
+DA:310,4
+DA:311,1
+DA:312,0
+DA:314,6
+DA:318,1
+DA:319,1
+DA:320,3
+DA:322,3
+DA:323,2
+DA:324,1
+DA:326,2
+DA:335,1
+DA:336,1
+DA:337,1
+DA:340,2
+DA:341,1
+DA:345,4
+DA:347,0
+DA:349,0
+DA:351,0
+DA:352,0
+DA:356,2
+DA:357,0
+LF:131
+LH:94
+end_of_record
+SF:lib\utils\network_utils.dart
+DA:35,51
+DA:40,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:49,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:63,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:74,0
+DA:77,0
+DA:78,0
+DA:80,0
+DA:83,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:96,0
+DA:97,0
+DA:99,0
+DA:103,0
+DA:104,0
+DA:105,0
+DA:106,0
+DA:107,0
+DA:108,0
+DA:110,0
+DA:114,0
+DA:115,0
+DA:116,0
+DA:118,0
+DA:119,0
+DA:122,0
+DA:123,0
+DA:126,0
+DA:129,0
+DA:134,0
+DA:135,0
+DA:136,0
+DA:137,0
+DA:138,0
+DA:139,0
+DA:140,0
+DA:141,0
+DA:143,0
+DA:147,0
+DA:148,0
+DA:149,0
+DA:150,0
+DA:151,0
+DA:153,0
+DA:155,0
+DA:157,0
+DA:158,0
+DA:159,0
+DA:163,0
+DA:165,0
+DA:166,0
+DA:167,0
+DA:168,0
+DA:171,0
+DA:172,0
+DA:175,0
+DA:176,0
+DA:179,0
+LF:82
+LH:1
+end_of_record
+SF:lib\utils\push_provider.dart
+DA:62,0
+DA:67,0
+DA:71,0
+DA:72,0
+DA:74,0
+DA:78,0
+DA:80,0
+DA:81,0
+DA:84,0
+DA:91,0
+DA:98,0
+DA:101,0
+DA:104,0
+DA:107,0
+DA:111,0
+DA:114,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:123,0
+DA:126,0
+DA:127,0
+DA:130,0
+DA:132,0
+DA:133,0
+DA:140,0
+DA:141,0
+DA:145,0
+DA:146,0
+DA:147,0
+DA:148,0
+DA:153,0
+DA:155,0
+DA:156,0
+DA:161,0
+DA:163,0
+DA:167,0
+DA:168,0
+DA:174,0
+DA:176,0
+DA:181,0
+DA:185,0
+DA:186,0
+DA:198,0
+DA:199,0
+DA:200,0
+DA:201,0
+DA:202,0
+DA:204,0
+DA:207,0
+DA:208,0
+DA:211,0
+DA:212,0
+DA:213,0
+DA:220,0
+DA:221,0
+DA:222,0
+DA:223,0
+DA:225,0
+DA:228,0
+DA:229,0
+DA:234,0
+DA:236,0
+DA:242,0
+DA:244,0
+DA:245,0
+DA:246,0
+DA:247,0
+DA:251,0
+DA:252,0
+DA:253,0
+DA:254,0
+DA:261,0
+DA:263,0
+DA:264,0
+DA:267,0
+DA:268,0
+DA:269,0
+DA:270,0
+DA:271,0
+DA:276,0
+DA:277,0
+DA:279,0
+DA:280,0
+DA:281,0
+DA:282,0
+DA:289,0
+DA:290,0
+DA:291,0
+DA:292,0
+DA:294,0
+DA:298,0
+DA:300,0
+DA:303,0
+DA:305,0
+DA:307,0
+DA:308,0
+DA:309,0
+DA:311,0
+DA:312,0
+DA:313,0
+DA:315,0
+DA:318,0
+DA:319,0
+DA:328,0
+DA:329,0
+DA:331,0
+DA:332,0
+DA:338,0
+DA:339,0
+DA:341,0
+DA:344,0
+DA:345,0
+DA:346,0
+DA:355,0
+DA:356,0
+DA:358,0
+DA:359,0
+DA:360,0
+DA:363,0
+DA:364,0
+DA:368,0
+DA:370,0
+DA:371,0
+DA:372,0
+DA:377,0
+DA:378,0
+DA:379,0
+DA:397,0
+DA:398,0
+DA:400,0
+DA:401,0
+DA:417,0
+DA:419,0
+DA:420,0
+DA:421,0
+DA:423,0
+DA:425,0
+DA:426,0
+DA:427,0
+DA:429,0
+DA:431,0
+DA:433,0
+DA:435,0
+DA:438,0
+DA:439,0
+LF:146
+LH:0
+end_of_record
+SF:lib\state_notifiers\settings_notifier.dart
+DA:18,1
+DA:22,1
+DA:23,1
+DA:25,1
+DA:26,3
+DA:27,2
+DA:28,0
+DA:29,1
+DA:30,2
+DA:35,1
+DA:36,3
+DA:37,3
+DA:38,3
+DA:39,1
+DA:43,1
+DA:44,2
+DA:45,3
+DA:46,3
+DA:47,1
+DA:50,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:68,1
+DA:69,2
+DA:70,3
+DA:71,1
+DA:74,1
+DA:75,2
+DA:76,3
+DA:77,1
+DA:80,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:86,0
+DA:87,0
+DA:88,0
+DA:89,0
+DA:92,1
+DA:93,2
+DA:94,3
+DA:95,1
+DA:98,0
+DA:99,0
+DA:100,0
+DA:101,0
+DA:104,1
+DA:105,2
+DA:106,3
+DA:107,1
+DA:110,1
+DA:111,2
+DA:112,2
+DA:113,3
+DA:114,1
+DA:117,1
+DA:118,2
+DA:119,3
+DA:120,1
+DA:123,0
+DA:124,0
+DA:125,0
+DA:126,0
+DA:129,0
+DA:130,0
+DA:131,0
+DA:132,0
+LF:76
+LH:43
+end_of_record
+SF:lib\state_notifiers\token_folder_notifier.dart
+DA:12,1
+DA:14,1
+DA:15,1
+DA:18,8
+DA:20,1
+DA:21,3
+DA:22,2
+DA:23,1
+DA:24,0
+DA:25,0
+DA:30,1
+DA:31,2
+DA:32,1
+DA:33,2
+DA:36,1
+DA:37,2
+DA:38,1
+DA:39,2
+DA:42,1
+DA:43,3
+DA:44,1
+DA:45,2
+DA:48,1
+DA:49,2
+DA:50,1
+DA:51,2
+DA:54,0
+DA:55,0
+DA:56,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:62,0
+DA:64,0
+DA:65,0
+DA:66,0
+LF:36
+LH:24
+end_of_record
+SF:lib\state_notifiers\token_notifier.dart
+DA:40,0
+DA:49,1
+DA:60,1
+DA:61,1
+DA:62,1
+DA:64,1
+DA:67,1
+DA:68,2
+DA:69,1
+DA:70,1
+DA:71,1
+DA:82,1
+DA:83,2
+DA:84,2
+DA:86,0
+DA:87,0
+DA:90,0
+DA:93,3
+DA:94,2
+DA:99,1
+DA:100,2
+DA:101,2
+DA:102,1
+DA:103,0
+DA:104,0
+DA:108,0
+DA:109,0
+DA:113,3
+DA:114,2
+DA:115,1
+DA:119,1
+DA:120,2
+DA:121,2
+DA:123,0
+DA:124,0
+DA:127,2
+DA:129,0
+DA:130,0
+DA:133,0
+DA:136,1
+DA:137,2
+DA:142,1
+DA:143,2
+DA:144,1
+DA:145,2
+DA:146,1
+DA:147,1
+DA:148,0
+DA:150,2
+DA:151,1
+DA:152,0
+DA:153,0
+DA:156,0
+DA:157,0
+DA:158,0
+DA:161,2
+DA:162,1
+DA:166,1
+DA:167,2
+DA:168,3
+DA:170,2
+DA:172,0
+DA:173,0
+DA:176,0
+DA:177,0
+DA:180,2
+DA:181,1
+DA:186,1
+DA:187,2
+DA:191,2
+DA:192,1
+DA:193,1
+DA:195,0
+DA:200,0
+DA:201,0
+DA:203,2
+DA:204,1
+DA:208,0
+DA:209,0
+DA:211,0
+DA:213,0
+DA:218,0
+DA:221,0
+DA:233,1
+DA:234,2
+DA:235,2
+DA:236,2
+DA:237,2
+DA:239,0
+DA:240,0
+DA:243,1
+DA:244,1
+DA:245,2
+DA:250,1
+DA:251,2
+DA:252,1
+DA:254,1
+DA:255,1
+DA:256,0
+DA:257,0
+DA:259,1
+DA:260,6
+DA:264,1
+DA:265,0
+DA:266,0
+DA:268,1
+DA:269,2
+DA:282,2
+DA:285,2
+DA:288,0
+DA:290,2
+DA:293,2
+DA:296,0
+DA:299,0
+DA:300,0
+DA:302,0
+DA:303,0
+DA:304,0
+DA:305,0
+DA:306,0
+DA:313,0
+DA:314,0
+DA:316,0
+DA:317,0
+DA:319,0
+DA:320,0
+DA:321,0
+DA:323,0
+DA:326,1
+DA:328,1
+DA:330,0
+DA:335,0
+DA:337,0
+DA:338,0
+DA:341,0
+DA:347,0
+DA:348,0
+DA:349,0
+DA:350,0
+DA:353,1
+DA:354,1
+DA:355,3
+DA:356,1
+DA:357,0
+DA:360,1
+DA:363,1
+DA:364,1
+DA:365,0
+DA:368,1
+DA:371,0
+DA:373,0
+DA:374,0
+DA:375,0
+DA:376,0
+DA:377,0
+DA:378,0
+DA:382,0
+DA:384,0
+DA:385,0
+DA:386,0
+DA:387,0
+DA:388,0
+DA:391,0
+DA:392,0
+DA:395,0
+DA:396,0
+DA:399,1
+DA:401,2
+DA:403,0
+DA:406,2
+DA:407,3
+DA:408,1
+DA:409,0
+DA:412,2
+DA:413,0
+DA:417,2
+DA:418,0
+DA:420,0
+DA:421,0
+DA:422,0
+DA:423,0
+DA:426,0
+DA:430,1
+DA:431,3
+DA:432,3
+DA:434,0
+DA:437,3
+DA:439,2
+DA:440,2
+DA:441,2
+DA:442,1
+DA:443,0
+DA:444,0
+DA:447,0
+DA:449,0
+DA:451,0
+DA:454,0
+DA:459,0
+DA:461,0
+DA:464,0
+DA:465,0
+DA:466,0
+DA:467,0
+DA:468,0
+DA:471,0
+DA:476,0
+DA:477,0
+DA:478,0
+DA:479,0
+DA:480,0
+DA:481,0
+DA:482,0
+DA:483,0
+DA:484,0
+DA:488,0
+DA:489,0
+DA:491,0
+DA:495,0
+DA:496,0
+DA:498,0
+DA:501,0
+DA:502,0
+DA:504,0
+DA:506,0
+DA:509,0
+DA:512,0
+DA:513,0
+DA:514,0
+DA:518,0
+DA:520,0
+DA:523,0
+DA:524,0
+DA:525,0
+DA:528,0
+DA:531,0
+DA:532,0
+DA:533,0
+DA:537,0
+DA:542,0
+DA:545,0
+DA:547,0
+DA:550,0
+DA:551,0
+DA:552,0
+DA:553,0
+DA:556,0
+DA:557,0
+DA:558,0
+DA:559,0
+DA:563,0
+DA:564,0
+DA:565,0
+DA:569,0
+DA:587,1
+DA:588,2
+DA:590,0
+DA:593,0
+DA:594,0
+DA:596,0
+DA:597,0
+DA:599,0
+DA:600,0
+DA:601,0
+DA:611,0
+DA:612,0
+DA:613,0
+DA:614,0
+DA:616,0
+DA:620,0
+DA:621,0
+DA:622,0
+DA:623,0
+DA:624,0
+DA:626,0
+DA:627,0
+DA:633,0
+DA:645,1
+DA:649,1
+DA:651,0
+DA:654,1
+DA:655,4
+DA:656,1
+DA:657,1
+DA:660,0
+DA:661,0
+DA:662,0
+DA:663,0
+DA:664,0
+DA:667,1
+DA:669,1
+DA:670,5
+DA:672,0
+DA:673,0
+DA:681,0
+DA:682,0
+DA:684,0
+DA:685,0
+DA:687,0
+DA:689,0
+DA:690,0
+DA:691,0
+DA:695,1
+DA:696,2
+DA:697,4
+DA:698,1
+DA:699,0
+DA:702,4
+DA:704,1
+DA:706,2
+DA:707,0
+DA:709,3
+DA:710,3
+DA:711,1
+DA:715,1
+DA:716,6
+DA:719,0
+DA:720,0
+DA:721,0
+DA:723,0
+LF:319
+LH:121
+end_of_record
+SF:lib\utils\firebase_utils.dart
+DA:20,1
+DA:22,1
+DA:23,1
+DA:27,0
+DA:32,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:56,0
+DA:59,0
+DA:60,0
+DA:63,0
+DA:65,0
+DA:66,0
+DA:68,0
+DA:69,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:75,0
+DA:79,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:84,0
+DA:88,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:96,0
+DA:99,0
+DA:100,0
+DA:101,0
+DA:104,0
+DA:106,0
+DA:107,0
+DA:108,0
+DA:112,0
+DA:121,1
+DA:124,1
+DA:125,1
+DA:126,1
+DA:127,3
+DA:132,1
+DA:134,0
+DA:135,0
+DA:141,0
+DA:156,3
+DA:157,3
+DA:182,0
+DA:183,0
+DA:185,0
+DA:186,0
+DA:187,0
+DA:188,0
+DA:189,0
+DA:190,0
+DA:193,0
+DA:194,0
+DA:195,0
+DA:200,0
+DA:201,0
+DA:202,0
+DA:205,4
+DA:208,0
+DA:209,0
+DA:210,0
+DA:212,0
+LF:79
+LH:12
+end_of_record
+SF:lib\utils\lock_auth.dart
+DA:19,0
+DA:21,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:38,0
+DA:39,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:60,0
+DA:61,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:70,0
+DA:76,0
+DA:78,0
+LF:32
+LH:0
+end_of_record
+SF:lib\utils\utils.dart
+DA:35,1
+DA:36,5
+DA:46,1
+DA:47,1
+DA:49,3
+DA:50,7
+DA:53,1
+DA:69,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:76,0
+DA:77,0
+DA:79,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:87,0
+DA:91,0
+DA:92,0
+DA:95,0
+DA:96,0
+DA:103,0
+DA:104,0
+DA:105,0
+DA:106,0
+DA:109,0
+DA:111,0
+DA:112,0
+LF:29
+LH:7
+end_of_record
+SF:lib\utils\app_info_utils.dart
+DA:11,0
+DA:12,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:25,0
+DA:26,0
+DA:28,0
+DA:29,0
+DA:31,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:37,0
+DA:38,0
+DA:40,0
+DA:41,0
+DA:43,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:54,0
+DA:55,0
+DA:57,0
+DA:58,0
+DA:60,0
+DA:61,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:84,0
+DA:86,0
+DA:87,0
+DA:89,0
+DA:90,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:99,0
+DA:100,0
+DA:101,0
+DA:102,0
+DA:103,0
+LF:71
+LH:0
+end_of_record
SF:lib\utils\crypto_utils.dart
+DA:31,1
+DA:32,1
+DA:33,1
DA:34,1
DA:35,1
-DA:36,1
DA:37,1
DA:38,1
+DA:39,1
DA:40,1
-DA:41,1
-DA:42,1
-DA:43,1
-DA:46,3
-DA:48,1
-DA:52,1
+DA:43,3
+DA:45,1
+DA:49,1
+DA:51,1
+DA:53,4
DA:54,1
-DA:56,4
-DA:57,1
-DA:59,2
-DA:62,1
-DA:64,2
+DA:56,2
+DA:59,1
+DA:61,2
+DA:64,1
DA:67,1
+DA:69,1
DA:70,1
-DA:72,1
-DA:73,1
-DA:76,3
+DA:73,3
+DA:77,2
+DA:78,2
DA:80,2
DA:81,2
-DA:83,2
-DA:84,2
-DA:85,4
-DA:86,4
-DA:88,6
-DA:93,2
-DA:94,4
-DA:95,4
-DA:96,4
-DA:99,5
-DA:100,6
-DA:101,6
-DA:102,10
-DA:105,2
-DA:107,2
-DA:114,3
-DA:115,3
-DA:116,3
-DA:117,3
-LF:44
-LH:44
+DA:82,4
+DA:83,4
+DA:85,6
+LF:30
+LH:30
+end_of_record
+SF:lib\widgets\home_widgets\home_widget_action.dart
+DA:12,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:39,0
+DA:47,0
+DA:48,0
+DA:58,0
+DA:60,0
+DA:61,0
+LF:18
+LH:0
+end_of_record
+SF:lib\widgets\home_widgets\home_widget_background.dart
+DA:8,0
+DA:16,0
+DA:17,0
+DA:27,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+LF:11
+LH:0
+end_of_record
+SF:lib\widgets\home_widgets\home_widget_configure.dart
+DA:9,0
+DA:16,0
+DA:17,0
+DA:27,0
+DA:34,0
+DA:35,0
+DA:37,0
+DA:38,0
+LF:8
+LH:0
+end_of_record
+SF:lib\widgets\home_widgets\home_widget_copied.dart
+DA:8,0
+DA:14,0
+DA:15,0
+DA:25,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:39,0
+DA:42,0
+LF:11
+LH:0
+end_of_record
+SF:lib\widgets\home_widgets\home_widget_hidden.dart
+DA:12,0
+DA:22,0
+DA:23,0
+DA:39,0
+DA:49,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:58,0
+LF:13
+LH:0
+end_of_record
+SF:lib\widgets\home_widgets\home_widget_otp.dart
+DA:12,0
+DA:22,0
+DA:23,0
+DA:39,0
+DA:49,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:59,0
+DA:60,0
+DA:62,0
+DA:65,0
+DA:67,0
+DA:72,0
+DA:74,0
+DA:77,0
+DA:78,0
+DA:79,0
+LF:20
+LH:0
+end_of_record
+SF:lib\widgets\home_widgets\home_widget_unlinked.dart
+DA:8,0
+DA:14,0
+DA:15,0
+DA:25,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:34,0
+DA:37,0
+LF:11
+LH:0
+end_of_record
+SF:lib\utils\image_converter.dart
+DA:13,0
+DA:15,0
+DA:17,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:51,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:62,0
+DA:67,0
+DA:68,0
+DA:71,0
+DA:72,0
+DA:74,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:79,0
+DA:80,0
+DA:82,0
+DA:84,0
+DA:86,0
+DA:90,0
+DA:91,0
+DA:93,0
+DA:96,0
+DA:105,0
+DA:108,0
+DA:109,0
+DA:110,0
+DA:111,0
+DA:112,0
+DA:121,0
+DA:122,0
+DA:127,0
+DA:132,0
+DA:133,0
+DA:139,0
+DA:140,0
+DA:147,0
+DA:152,0
+DA:153,0
+DA:160,0
+DA:161,0
+DA:168,0
+DA:173,0
+DA:174,0
+DA:181,0
+DA:182,0
+DA:195,0
+DA:196,0
+DA:202,0
+DA:203,0
+DA:213,0
+DA:217,0
+DA:218,0
+DA:220,0
+DA:221,0
+DA:223,0
+DA:224,0
+DA:225,0
+DA:228,0
+DA:229,0
+DA:230,0
+DA:233,0
+DA:234,0
+DA:236,0
+DA:237,0
+DA:241,0
+DA:245,0
+DA:246,0
+DA:248,0
+DA:251,0
+DA:252,0
+DA:253,0
+DA:256,0
+DA:257,0
+DA:258,0
+DA:261,0
+DA:262,0
+DA:265,0
+DA:266,0
+LF:106
+LH:0
+end_of_record
+SF:lib\utils\pi_mailer.dart
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:21,0
+DA:29,0
+DA:31,0
+DA:32,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:52,0
+DA:55,0
+LF:22
+LH:0
+end_of_record
+SF:lib\utils\patch_notes_utils.dart
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:28,0
+DA:29,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:39,0
+LF:18
+LH:0
+end_of_record
+SF:lib\widgets\dialog_widgets\patch_notes_dialog.dart
+DA:15,0
+DA:17,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:31,0
+DA:32,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:54,0
+DA:55,0
+DA:57,0
+DA:60,0
+DA:61,0
+DA:63,0
+DA:66,0
+DA:69,0
+DA:70,0
+DA:80,0
+DA:86,0
+DA:87,0
+DA:88,0
+DA:89,0
+DA:90,0
+DA:92,0
+DA:93,0
+DA:94,0
+LF:46
+LH:0
+end_of_record
+SF:lib\utils\pi_notifications.dart
+DA:9,0
+DA:11,0
+DA:13,0
+DA:15,0
+DA:16,0
+DA:21,0
+DA:24,0
+DA:25,0
+DA:34,0
+DA:37,0
+DA:38,0
+DA:39,0
+LF:12
+LH:0
+end_of_record
+SF:lib\views\add_token_manually_view\add_token_manually_view_widgets\labeled_dropdown_button.dart
+DA:13,0
+DA:22,0
+DA:23,0
+DA:27,0
+DA:29,0
+DA:31,0
+DA:32,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:41,0
+DA:43,0
+DA:45,0
+DA:46,0
+DA:48,0
+DA:49,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:59,0
+DA:60,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:65,0
+LF:26
+LH:0
+end_of_record
+SF:lib\views\view_interface.dart
+DA:6,0
+DA:10,17
+DA:14,17
+DA:18,17
+DA:22,17
+LF:5
+LH:4
+end_of_record
+SF:lib\views\import_tokens_view\pages\import_start_page.dart
+DA:25,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:30,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:38,0
+DA:40,0
+DA:41,0
+DA:43,0
+DA:51,0
+DA:57,0
+DA:58,0
+DA:68,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:75,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:81,0
+DA:82,0
+DA:84,0
+DA:86,0
+DA:88,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:95,0
+DA:96,0
+DA:97,0
+DA:100,0
+DA:101,0
+DA:103,0
+DA:104,0
+DA:105,0
+DA:106,0
+DA:110,0
+DA:111,0
+DA:112,0
+DA:114,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:121,0
+DA:122,0
+DA:123,0
+DA:124,0
+DA:125,0
+DA:126,0
+DA:127,0
+DA:128,0
+DA:130,0
+DA:131,0
+DA:132,0
+DA:147,0
+DA:148,0
+DA:150,0
+DA:151,0
+DA:153,0
+DA:156,0
+DA:157,0
+DA:158,0
+DA:161,0
+DA:162,0
+DA:163,0
+DA:166,0
+DA:167,0
+DA:168,0
+DA:169,0
+DA:174,0
+DA:180,0
+DA:181,0
+DA:182,0
+DA:183,0
+DA:184,0
+DA:185,0
+DA:187,0
+DA:190,0
+DA:192,0
+DA:195,0
+DA:196,0
+DA:198,0
+DA:199,0
+DA:202,0
+DA:203,0
+DA:204,0
+DA:205,0
+DA:208,0
+DA:209,0
+DA:210,0
+DA:211,0
+DA:212,0
+DA:213,0
+DA:215,0
+DA:216,0
+DA:219,0
+DA:220,0
+DA:224,0
+DA:225,0
+DA:227,0
+DA:231,0
+DA:232,0
+DA:233,0
+DA:236,0
+DA:241,0
+DA:242,0
+DA:243,0
+DA:246,0
+DA:247,0
+DA:248,0
+DA:251,0
+DA:252,0
+DA:253,0
+DA:254,0
+DA:255,0
+DA:256,0
+DA:258,0
+DA:261,0
+DA:262,0
+DA:265,0
+DA:266,0
+DA:268,0
+DA:270,0
+DA:273,0
+DA:274,0
+DA:277,0
+DA:281,0
+DA:282,0
+DA:285,0
+DA:289,0
+DA:290,0
+DA:291,0
+DA:294,0
+DA:295,0
+DA:296,0
+DA:299,0
+DA:300,0
+DA:301,0
+DA:302,0
+DA:303,0
+DA:305,0
+DA:307,0
+DA:309,0
+DA:310,0
+DA:311,0
+DA:314,0
+DA:315,0
+DA:316,0
+DA:317,0
+DA:318,0
+DA:319,0
+DA:321,0
+DA:327,0
+DA:328,0
+DA:329,0
+DA:330,0
+DA:331,0
+DA:332,0
+DA:334,0
+LF:164
+LH:0
+end_of_record
+SF:lib\views\import_tokens_view\pages\select_import_type_page.dart
+DA:15,0
+DA:17,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:23,0
+DA:24,0
+DA:26,0
+DA:28,0
+DA:30,0
+DA:39,0
+DA:40,0
+DA:44,0
+DA:45,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:59,0
+DA:65,0
+DA:66,0
+DA:68,0
+DA:71,0
+DA:74,0
+DA:83,0
+DA:84,0
+LF:32
+LH:0
+end_of_record
+SF:lib\views\import_tokens_view\pages\import_encrypted_data_page.dart
+DA:18,0
+DA:26,0
+DA:28,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:42,0
+DA:43,0
+DA:45,0
+DA:47,0
+DA:49,0
+DA:55,0
+DA:56,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:62,0
+DA:63,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:71,0
+DA:72,0
+DA:74,0
+DA:78,0
+DA:79,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:100,0
+DA:102,0
+DA:104,0
+DA:105,0
+DA:107,0
+DA:108,0
+DA:109,0
+DA:110,0
+DA:112,0
+DA:113,0
+DA:114,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:122,0
+DA:125,0
+DA:126,0
+DA:127,0
+DA:140,0
+DA:141,0
+DA:142,0
+DA:143,0
+DA:144,0
+DA:146,0
+LF:57
+LH:0
+end_of_record
+SF:lib\views\import_tokens_view\pages\import_plain_tokens_page.dart
+DA:20,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:36,0
+DA:38,0
+DA:39,0
+DA:48,0
+DA:50,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:59,0
+DA:61,0
+DA:62,0
+DA:65,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:72,0
+DA:73,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:85,0
+DA:86,0
+DA:87,0
+DA:93,0
+DA:95,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:99,0
+DA:100,0
+DA:101,0
+DA:104,0
+DA:105,0
+DA:108,0
+DA:111,0
+DA:112,0
+DA:113,0
+DA:115,0
+DA:119,0
+DA:120,0
+DA:121,0
+DA:123,0
+DA:124,0
+DA:125,0
+DA:126,0
+DA:128,0
+DA:129,0
+DA:135,0
+DA:136,0
+DA:137,0
+DA:138,0
+DA:139,0
+DA:141,0
+DA:142,0
+DA:143,0
+DA:145,0
+DA:147,0
+DA:149,0
+DA:150,0
+DA:151,0
+DA:153,0
+DA:154,0
+DA:156,0
+DA:157,0
+DA:158,0
+DA:160,0
+DA:161,0
+DA:170,0
+DA:171,0
+DA:179,0
+DA:186,0
+DA:188,0
+DA:189,0
+DA:191,0
+DA:192,0
+DA:193,0
+DA:194,0
+DA:206,0
+DA:207,0
+DA:208,0
+DA:210,0
+DA:213,0
+DA:214,0
+DA:215,0
+DA:216,0
+DA:217,0
+DA:218,0
+DA:221,0
+DA:222,0
+LF:100
+LH:0
+end_of_record
+SF:lib\views\import_tokens_view\widgets\conflicted_import_tokens_list.dart
+DA:6,0
+DA:22,0
+DA:24,0
+DA:27,0
+DA:28,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:52,0
+DA:53,0
+DA:54,0
+LF:16
+LH:0
+end_of_record
+SF:lib\views\import_tokens_view\widgets\conflicted_import_tokens_tile.dart
+DA:11,0
+DA:16,0
+DA:18,0
+DA:19,0
+DA:25,0
+DA:27,0
+DA:28,0
+DA:31,0
+DA:32,0
+DA:34,0
+DA:37,0
+DA:38,0
+DA:44,0
+DA:45,0
+DA:47,0
+DA:48,0
+DA:50,0
+DA:51,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:57,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:68,0
+DA:71,0
+DA:74,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:80,0
+DA:82,0
+DA:83,0
+DA:84,0
+DA:85,0
+DA:86,0
+DA:87,0
+DA:88,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:94,0
+DA:98,0
+DA:99,0
+DA:100,0
+DA:101,0
+DA:102,0
+DA:103,0
+DA:105,0
+DA:112,0
+DA:113,0
+DA:114,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:120,0
+DA:121,0
+DA:125,0
+DA:126,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:130,0
+DA:133,0
+DA:134,0
+DA:135,0
+DA:136,0
+DA:138,0
+DA:140,0
+DA:141,0
+DA:142,0
+DA:143,0
+DA:145,0
+DA:147,0
+DA:148,0
+DA:161,0
+LF:79
+LH:0
+end_of_record
+SF:lib\views\import_tokens_view\widgets\failed_imports_list.dart
+DA:8,0
+DA:13,0
+DA:15,0
+DA:17,0
+DA:18,0
+DA:20,0
+DA:21,0
+DA:23,0
+DA:26,0
+DA:27,0
+DA:29,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:39,0
+DA:41,0
+DA:42,0
+LF:18
+LH:0
+end_of_record
+SF:lib\views\import_tokens_view\widgets\no_conflict_import_tokens_list.dart
+DA:7,0
+DA:23,0
+DA:24,0
+DA:28,0
+DA:30,0
+DA:33,0
+DA:34,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:54,0
+DA:55,0
+DA:58,0
+LF:15
+LH:0
+end_of_record
+SF:lib\views\import_tokens_view\widgets\no_conflict_import_tokens_tile.dart
+DA:13,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+LF:13
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\token_widget_builder.dart
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+LF:15
+LH:0
+end_of_record
+SF:lib\widgets\push_request_listener.dart
+DA:10,0
+DA:12,0
+DA:13,0
+DA:17,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:25,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:32,0
+DA:34,0
+LF:14
+LH:0
+end_of_record
+SF:lib\widgets\status_bar.dart
+DA:11,0
+DA:13,0
+DA:14,0
+DA:27,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:34,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:46,0
+DA:49,0
+DA:51,0
+DA:52,0
+DA:54,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:64,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:79,0
+DA:80,0
+DA:90,0
+DA:92,0
+DA:93,0
+DA:105,0
+DA:107,0
+DA:108,0
+DA:109,0
+DA:110,0
+DA:111,0
+DA:113,0
+DA:114,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:122,0
+DA:123,0
+DA:124,0
+DA:127,0
+DA:130,0
+DA:132,0
+DA:133,0
+DA:134,0
+DA:135,0
+DA:136,0
+DA:142,0
+DA:143,0
+DA:144,0
+DA:145,0
+DA:146,0
+DA:147,0
+DA:148,0
+DA:149,0
+DA:150,0
+DA:151,0
+DA:155,0
+DA:160,0
+DA:162,0
+DA:163,0
+DA:164,0
+DA:165,0
+DA:166,0
+DA:168,0
+DA:172,0
+DA:173,0
+DA:174,0
+DA:175,0
+DA:179,0
+DA:180,0
+DA:181,0
+DA:182,0
+DA:183,0
+DA:184,0
+DA:187,0
+DA:189,0
+DA:191,0
+DA:192,0
+DA:193,0
+DA:197,0
+DA:198,0
+DA:199,0
+DA:207,0
+DA:208,0
+DA:210,0
+DA:212,0
+DA:213,0
+DA:214,0
+DA:217,0
+LF:100
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\app_bar_item.dart
+DA:4,0
+DA:10,0
+DA:11,0
+DA:12,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:20,0
+LF:8
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\connectivity_listener.dart
+DA:11,0
+DA:13,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:24,0
+LF:9
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\expandable_appbar.dart
+DA:10,0
+DA:17,0
+DA:18,0
+DA:29,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:49,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:60,0
+DA:61,0
+DA:66,0
+DA:68,0
+DA:69,0
+DA:71,0
+DA:74,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:84,0
+DA:85,0
+DA:86,0
+DA:87,0
+DA:89,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:100,0
+DA:101,0
+DA:102,0
+DA:103,0
+DA:104,0
+DA:105,0
+DA:106,0
+DA:107,0
+DA:108,0
+DA:111,0
+DA:112,0
+DA:117,0
+DA:118,0
+DA:119,0
+DA:120,0
+DA:122,0
+DA:123,0
+DA:130,0
+DA:131,0
+LF:63
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\main_view_navigation_bar.dart
+DA:17,17
+DA:19,0
+DA:21,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:30,0
+DA:31,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:41,0
+DA:43,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:49,0
+DA:50,0
+DA:53,0
+DA:54,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:84,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:99,0
+DA:100,0
+DA:101,0
+DA:102,0
+DA:103,0
+DA:104,0
+DA:106,0
+DA:110,0
+DA:111,0
+DA:113,0
+DA:121,0
+DA:122,0
+DA:123,0
+DA:124,0
+DA:125,0
+DA:126,0
+DA:127,0
+DA:128,0
+LF:69
+LH:1
+end_of_record
+SF:lib\views\main_view\main_view_widgets\main_view_tokens_list.dart
+DA:21,0
+DA:23,0
+DA:24,0
+DA:33,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:41,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:52,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:72,0
+DA:80,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:99,0
+DA:100,0
+DA:107,0
+DA:109,0
+LF:43
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\main_view_tokens_list_filtered.dart
+DA:14,17
+DA:16,0
+DA:18,0
+DA:19,0
+DA:21,0
+DA:22,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:44,0
+DA:45,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:59,0
+LF:30
+LH:1
+end_of_record
+SF:lib\views\main_view\main_view_widgets\custom_paint_navigation_bar.dart
+DA:8,0
+DA:23,0
+DA:26,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:51,0
+LF:24
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\drag_target_divider.dart
+DA:20,34
+DA:29,0
+DA:30,0
+DA:36,0
+DA:38,0
+DA:39,0
+DA:43,0
+DA:44,0
+DA:48,0
+DA:50,0
+DA:51,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:59,0
+DA:63,0
+DA:64,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:84,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:97,0
+DA:104,0
+DA:106,0
+DA:107,0
+DA:108,0
+DA:109,0
+DA:110,0
+DA:111,0
+DA:115,0
+DA:117,0
+DA:119,0
+DA:122,0
+DA:125,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:133,0
+DA:137,0
+DA:139,0
+DA:140,0
+DA:142,0
+DA:143,0
+DA:145,0
+DA:148,0
+DA:149,0
+DA:153,0
+DA:154,0
+DA:155,0
+DA:157,0
+LF:64
+LH:1
+end_of_record
+SF:lib\widgets\drag_item_scroller.dart
+DA:10,0
+DA:29,0
+DA:36,0
+DA:38,0
+DA:39,0
+DA:45,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:55,0
+DA:56,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:62,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:68,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:84,0
+DA:85,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:97,0
+DA:99,0
+DA:100,0
+DA:101,0
+DA:102,0
+DA:107,0
+DA:109,0
+DA:110,0
+DA:111,0
+DA:112,0
+DA:113,0
+DA:114,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:118,0
+DA:119,0
+DA:120,0
+DA:121,0
+DA:122,0
+DA:123,0
+DA:125,0
+DA:126,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:133,0
+DA:134,0
+DA:136,0
+DA:137,0
+DA:138,0
+DA:139,0
+DA:140,0
+DA:143,0
+LF:71
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\filter_token_widget.dart
+DA:9,0
+DA:11,0
+DA:12,0
+DA:16,17
+DA:18,0
+DA:19,0
+DA:27,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:43,0
+DA:44,0
+DA:46,0
+DA:50,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:62,0
+LF:27
+LH:1
+end_of_record
+SF:lib\views\main_view\main_view_widgets\folder_widgets\add_token_folder_dialog.dart
+DA:12,0
+DA:14,0
+DA:16,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:38,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:50,0
+DA:51,0
+LF:24
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\folder_widgets\token_folder_actions.dart\delete_token_folder_action.dart
+DA:15,0
+DA:16,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:25,0
+DA:28,0
+DA:30,0
+DA:31,0
+DA:40,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:46,0
+DA:47,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:67,0
+DA:68,0
+LF:32
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\folder_widgets\token_folder_actions.dart\lock_token_folder_action.dart
+DA:13,0
+DA:14,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:23,0
+DA:26,0
+DA:28,0
+DA:29,0
+LF:12
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\folder_widgets\token_folder_actions.dart\rename_token_folder_action.dart
+DA:15,0
+DA:17,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:26,0
+DA:29,0
+DA:31,0
+DA:32,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:48,0
+DA:49,0
+DA:51,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:63,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:70,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:83,0
+DA:86,0
+DA:89,0
+LF:41
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\folder_widgets\token_folder_expandable.dart
+DA:29,0
+DA:31,0
+DA:32,0
+DA:40,0
+DA:42,0
+DA:43,0
+DA:45,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:53,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:64,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:72,0
+DA:74,0
+DA:75,0
+DA:76,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:85,0
+DA:87,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:97,0
+DA:98,0
+DA:101,0
+DA:102,0
+DA:104,0
+DA:105,0
+DA:107,0
+DA:110,0
+DA:111,0
+DA:112,0
+DA:113,0
+DA:116,0
+DA:118,0
+DA:119,0
+DA:120,0
+DA:121,0
+DA:122,0
+DA:123,0
+DA:124,0
+DA:125,0
+DA:131,0
+DA:132,0
+DA:133,0
+DA:134,0
+DA:136,0
+DA:139,0
+DA:140,0
+DA:141,0
+DA:142,0
+DA:144,0
+DA:145,0
+DA:146,0
+DA:147,0
+DA:149,0
+DA:150,0
+DA:153,0
+DA:155,0
+DA:156,0
+DA:157,0
+DA:158,0
+DA:161,0
+DA:164,0
+DA:166,0
+DA:167,0
+DA:168,0
+DA:173,0
+DA:174,0
+DA:175,0
+DA:176,0
+DA:178,0
+DA:180,0
+DA:182,0
+DA:183,0
+DA:185,0
+DA:187,0
+DA:188,0
+DA:189,0
+DA:190,0
+DA:191,0
+DA:192,0
+DA:193,0
+DA:194,0
+DA:195,0
+DA:196,0
+DA:197,0
+DA:198,0
+DA:199,0
+DA:222,0
+DA:224,0
+DA:226,0
+DA:227,0
+DA:232,0
+DA:233,0
+DA:245,0
+DA:247,0
+DA:248,0
+DA:249,0
+DA:250,0
+DA:251,0
+DA:253,0
+DA:254,0
+DA:255,0
+LF:120
+LH:0
+end_of_record
+SF:lib\widgets\custom_trailing.dart
+DA:15,17
+DA:19,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+LF:10
+LH:1
+end_of_record
+SF:lib\views\main_view\main_view_widgets\folder_widgets\token_folder_widget.dart
+DA:14,0
+DA:16,0
+DA:18,0
+DA:19,0
+DA:21,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:27,0
+DA:28,0
+DA:30,0
+DA:31,0
+DA:33,0
+DA:34,0
+DA:36,0
+DA:38,0
+DA:40,0
+DA:42,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:58,0
+DA:60,0
+LF:26
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\loading_indicator.dart
+DA:10,0
+DA:12,0
+DA:13,0
+DA:15,0
+DA:16,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:27,17
+DA:29,0
+DA:31,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:38,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+LF:21
+LH:1
+end_of_record
+SF:lib\widgets\focused_item_as_overlay.dart
+DA:23,0
+DA:33,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:44,0
+DA:55,0
+DA:64,0
+DA:65,0
+DA:81,0
+DA:82,0
+DA:84,0
+DA:86,0
+DA:87,0
+DA:88,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:97,0
+DA:98,0
+DA:99,0
+DA:100,0
+DA:106,0
+DA:109,0
+DA:111,0
+DA:112,0
+DA:114,0
+DA:117,0
+DA:119,0
+DA:120,0
+DA:121,0
+DA:125,0
+DA:126,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:130,0
+DA:131,0
+DA:135,0
+DA:136,0
+DA:137,0
+DA:138,0
+DA:139,0
+DA:140,0
+DA:141,0
+DA:145,0
+DA:146,0
+DA:147,0
+DA:149,0
+DA:151,0
+DA:152,0
+DA:153,0
+DA:155,0
+DA:156,0
+DA:157,0
+DA:158,0
+DA:159,0
+DA:160,0
+DA:161,0
+DA:162,0
+DA:166,0
+DA:172,0
+DA:173,0
+DA:175,0
+DA:178,0
+DA:179,0
+DA:181,0
+DA:182,0
+DA:183,0
+DA:184,0
+DA:185,0
+DA:186,0
+DA:187,0
+DA:188,0
+DA:189,0
+DA:190,0
+DA:191,0
+DA:192,0
+DA:194,0
+DA:196,0
+DA:197,0
+DA:198,0
+DA:199,0
+DA:204,0
+DA:205,0
+DA:206,0
+DA:207,0
+DA:209,0
+DA:215,0
+DA:216,0
+DA:217,0
+DA:218,0
+DA:219,0
+DA:220,0
+DA:222,0
+DA:234,0
+DA:235,0
+DA:236,0
+DA:243,0
+DA:244,0
+DA:245,0
+DA:248,0
+DA:249,0
+DA:250,0
+DA:251,0
+DA:252,0
+DA:253,0
+DA:254,0
+DA:258,0
+DA:265,0
+DA:266,0
+DA:267,0
+DA:268,0
+DA:269,0
+DA:273,0
+DA:274,0
+DA:275,0
+DA:280,0
+DA:283,0
+DA:285,0
+DA:288,0
+DA:291,0
+LF:129
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\main_view_navigation_buttons\license_push_view_button.dart
+DA:13,17
+DA:15,0
+DA:17,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:29,0
+DA:30,0
+DA:31,0
+LF:13
+LH:1
+end_of_record
+SF:lib\views\main_view\main_view_widgets\main_view_navigation_buttons\qr_scanner_button.dart
+DA:13,17
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:27,0
+DA:30,0
+DA:31,0
+DA:34,0
+LF:13
+LH:1
+end_of_record
+SF:lib\widgets\deactivateable_refresh_indicator.dart
+DA:8,0
+DA:15,0
+DA:17,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:22,0
+DA:24,0
+LF:8
+LH:0
+end_of_record
+SF:lib\widgets\introduction_widgets\token_introduction.dart
+DA:11,0
+DA:13,0
+DA:15,0
+DA:16,0
+DA:18,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:25,0
+DA:26,0
+DA:28,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:35,0
+LF:15
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\no_token_screen.dart
+DA:6,17
+DA:8,0
+DA:10,0
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:29,0
+DA:30,0
+DA:33,0
+DA:34,0
+DA:35,0
+LF:18
+LH:1
+end_of_record
+SF:lib\views\main_view\main_view_widgets\sortable_widget_builder.dart
+DA:10,0
+DA:11,0
+DA:12,0
+DA:13,0
+LF:4
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\day_password_token_widgets\actions\edit_day_password_token_action.dart
+DA:21,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:34,0
+DA:36,0
+DA:37,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:45,0
+DA:47,0
+DA:48,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:62,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:69,0
+DA:70,0
+DA:74,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:81,0
+DA:82,0
+DA:85,0
+DA:86,0
+DA:87,0
+DA:91,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:98,0
+DA:99,0
+DA:101,0
+DA:105,0
+DA:106,0
+DA:108,0
+DA:109,0
+DA:110,0
+DA:111,0
+DA:116,0
+DA:118,0
+DA:119,0
+DA:120,0
+DA:121,0
+DA:126,0
+DA:127,0
+DA:128,0
+DA:131,0
+DA:132,0
+DA:133,0
+DA:136,0
+DA:137,0
+DA:138,0
+DA:142,0
+DA:143,0
+LF:66
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\token_action.dart
+DA:6,0
+LF:1
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\day_password_token_widgets\day_password_token_widget.dart
+DA:12,0
+DA:14,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:20,0
+LF:6
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\token_widget.dart
+DA:6,0
+LF:1
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\token_widget_base.dart
+DA:25,0
+DA:36,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:49,0
+DA:51,0
+DA:52,0
+DA:54,0
+DA:55,0
+DA:57,0
+DA:58,0
+DA:60,0
+DA:61,0
+DA:62,0
+DA:64,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:82,0
+DA:83,0
+DA:86,0
+DA:88,0
+DA:89,0
+DA:91,0
+DA:92,0
+LF:36
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\day_password_token_widgets\day_password_token_widget_tile.dart
+DA:22,0
+DA:24,0
+DA:25,0
+DA:32,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:48,0
+DA:50,0
+DA:51,0
+DA:54,0
+DA:55,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:61,0
+DA:64,0
+DA:65,0
+DA:69,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:75,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:84,0
+DA:86,0
+DA:87,0
+DA:88,0
+DA:89,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:97,0
+DA:98,0
+DA:102,0
+DA:103,0
+DA:104,0
+DA:105,0
+DA:106,0
+DA:107,0
+DA:108,0
+DA:110,0
+DA:111,0
+DA:112,0
+DA:114,0
+DA:116,0
+DA:119,0
+DA:120,0
+DA:121,0
+DA:122,0
+DA:124,0
+DA:126,0
+DA:127,0
+DA:128,0
+DA:131,0
+DA:132,0
+DA:136,0
+DA:137,0
+DA:138,0
+DA:139,0
+DA:140,0
+DA:141,0
+DA:142,0
+DA:143,0
+DA:144,0
+DA:146,0
+DA:152,0
+DA:154,0
+DA:156,0
+DA:157,0
+DA:158,0
+DA:159,0
+DA:161,0
+LF:92
+LH:0
end_of_record
-SF:lib\utils\utils.dart
-DA:37,1
-DA:38,5
-DA:48,1
-DA:49,1
-DA:51,3
-DA:52,7
-DA:55,1
-DA:58,4
-DA:59,8
-DA:60,8
-DA:65,2
-DA:73,8
-DA:74,8
-DA:75,8
-DA:76,48
-DA:77,16
-DA:80,5
-DA:81,15
-DA:85,1
-DA:86,2
+SF:lib\widgets\custom_texts.dart
+DA:48,0
+DA:60,0
+DA:62,0
+DA:63,0
+DA:65,0
+DA:66,0
+LF:6
+LH:0
+end_of_record
+SF:lib\widgets\hideable_widget_.dart
+DA:12,0
+DA:19,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:27,0
+LF:7
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\token_widget_tile.dart
+DA:6,0
+DA:19,0
+DA:31,0
+DA:32,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:40,0
+DA:42,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:49,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:56,0
+DA:67,0
+DA:71,0
+DA:73,0
+DA:74,0
+DA:75,0
+DA:77,0
+DA:78,0
+DA:83,0
+DA:87,0
+DA:88,0
+DA:93,0
+DA:97,0
+DA:99,0
+DA:100,0
+DA:107,0
+DA:109,0
+DA:110,0
+DA:111,0
+DA:113,0
+DA:116,0
+DA:117,0
+DA:118,0
+DA:119,0
+DA:120,0
+DA:121,0
+DA:128,0
+DA:132,0
+DA:133,0
+DA:135,0
+DA:136,0
+DA:137,0
+DA:139,0
+DA:140,0
+DA:144,0
+DA:145,0
+DA:148,0
+DA:149,0
+DA:150,0
+DA:151,0
+DA:152,0
+DA:153,0
+DA:163,0
+DA:164,0
+DA:165,0
+DA:167,0
+DA:169,0
+LF:65
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\default_token_actions\default_delete_action.dart
+DA:17,0
+DA:19,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:28,0
+DA:30,0
+DA:33,0
+DA:35,0
+DA:36,0
+DA:45,0
+DA:47,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:61,0
+DA:62,0
+DA:63,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:81,0
+DA:82,0
+DA:83,0
+LF:38
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\default_token_actions\default_edit_action.dart
+DA:19,0
+DA:21,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:30,0
+DA:32,0
+DA:33,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:40,0
+DA:42,0
+DA:43,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:60,0
+DA:61,0
+DA:65,0
+DA:68,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:84,0
+DA:86,0
+DA:87,0
+DA:88,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:97,0
+DA:100,0
+DA:103,0
+LF:45
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\default_token_actions\default_lock_action.dart
+DA:17,0
+DA:19,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:28,0
+DA:30,0
+DA:31,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:39,0
+DA:41,0
+DA:42,0
+LF:17
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\hotp_token_widgets\actions\edit_hotp_token_action.dart
+DA:22,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:35,0
+DA:37,0
+DA:38,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:46,0
+DA:48,0
+DA:49,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:62,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:77,0
+DA:78,0
+DA:81,0
+DA:82,0
+DA:83,0
DA:87,0
-DA:88,0
-DA:92,0
-DA:93,0
+DA:89,0
+DA:90,0
+DA:91,0
DA:94,0
+DA:95,0
DA:97,0
DA:101,0
DA:102,0
-DA:103,0
DA:104,0
DA:105,0
DA:106,0
DA:107,0
-DA:108,0
-DA:109,0
DA:112,0
-DA:113,0
+DA:114,0
+DA:115,0
DA:116,0
DA:117,0
DA:122,0
+DA:123,0
DA:124,0
-DA:126,0
-DA:132,0
-LF:43
-LH:20
+DA:127,0
+DA:128,0
+DA:129,0
+DA:133,0
+DA:134,0
+LF:61
+LH:0
end_of_record
-SF:lib\model\tokens\otp_token.dart
-DA:10,4
+SF:lib\views\main_view\main_view_widgets\token_widgets\hotp_token_widgets\hotp_token_widget.dart
+DA:13,0
+DA:18,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:24,0
+LF:6
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\hotp_token_widgets\hotp_token_widget_tile.dart
+DA:19,0
+DA:21,0
+DA:22,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:33,0
+DA:36,0
+DA:37,0
+DA:38,0
DA:40,0
+DA:41,0
DA:42,0
-LF:3
-LH:1
+DA:43,0
+DA:49,0
+DA:50,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
+DA:56,0
+DA:59,0
+DA:60,0
+DA:64,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:69,0
+DA:70,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:75,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:82,0
+DA:83,0
+DA:84,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:97,0
+DA:98,0
+DA:99,0
+DA:101,0
+DA:102,0
+DA:107,0
+DA:108,0
+DA:109,0
+DA:110,0
+DA:111,0
+DA:113,0
+LF:60
+LH:0
end_of_record
-SF:lib\model\tokens\hotp_token.dart
-DA:16,4
-DA:30,8
-DA:32,3
-DA:33,3
-DA:34,3
-DA:35,3
-DA:36,3
-DA:37,6
-DA:41,4
-DA:43,2
-DA:58,2
-DA:59,1
-DA:60,2
-DA:61,2
-DA:62,2
-DA:63,2
-DA:64,2
-DA:65,2
-DA:66,2
-DA:67,2
-DA:68,2
-DA:69,2
-DA:70,3
+SF:lib\views\main_view\main_view_widgets\token_widgets\push_token_widgets\actions\edit_push_token_action.dart
+DA:20,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:33,0
+DA:35,0
+DA:36,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:44,0
+DA:46,0
+DA:47,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:62,0
+DA:64,0
+DA:65,0
+DA:67,0
+DA:68,0
+DA:72,0
DA:73,0
+DA:74,0
DA:75,0
-DA:78,2
-DA:79,3
-DA:80,5
-DA:83,2
-DA:84,2
-DA:85,2
-DA:86,2
-DA:87,4
-DA:88,2
-DA:89,4
-DA:90,2
-DA:91,2
-DA:92,2
-DA:93,2
-DA:96,0
+DA:79,0
+DA:80,0
+DA:83,0
+DA:84,0
+DA:85,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:98,0
DA:101,0
DA:103,0
-LF:42
-LH:37
+DA:107,0
+DA:108,0
+DA:113,0
+DA:116,0
+DA:117,0
+DA:120,0
+DA:122,0
+DA:123,0
+DA:124,0
+DA:125,0
+DA:130,0
+DA:132,0
+DA:133,0
+DA:134,0
+DA:139,0
+DA:140,0
+DA:141,0
+DA:142,0
+DA:146,0
+DA:147,0
+DA:148,0
+DA:149,0
+DA:154,0
+DA:155,0
+DA:156,0
+DA:157,0
+DA:161,0
+DA:162,0
+DA:163,0
+DA:164,0
+DA:168,0
+DA:169,0
+DA:170,0
+DA:174,0
+DA:175,0
+LF:81
+LH:0
end_of_record
-SF:lib\model\tokens\hotp_token.g.dart
-DA:9,0
-DA:10,0
+SF:lib\widgets\enable_text_form_field_after_many_taps.dart
DA:11,0
-DA:12,0
-DA:13,0
-DA:14,0
+DA:19,0
+DA:20,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+LF:18
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\push_token_widgets\push_token_widget.dart
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:26,0
+DA:33,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:47,0
+LF:18
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\push_token_widgets\push_token_widget_tile.dart
DA:15,0
-DA:16,0
DA:17,0
-DA:18,0
DA:19,0
DA:20,0
DA:21,0
DA:22,0
+DA:23,0
+DA:24,0
DA:25,0
-DA:26,0
-DA:27,0
-DA:28,0
-DA:29,0
DA:30,0
DA:31,0
-DA:32,0
DA:33,0
DA:34,0
-DA:35,0
DA:36,0
DA:37,0
DA:38,0
-LF:28
+LF:16
LH:0
end_of_record
-SF:lib\utils\custom_int_buffer.dart
-DA:9,4
-DA:14,3
-DA:15,5
-DA:16,3
-DA:19,2
-DA:20,2
-DA:21,0
-DA:24,6
-DA:25,0
-DA:28,2
-DA:31,3
-DA:32,14
-DA:33,6
-DA:36,3
-DA:38,6
-DA:40,2
-DA:42,2
-LF:17
-LH:15
-end_of_record
-SF:lib\utils\custom_int_buffer.g.dart
-DA:9,1
-DA:10,1
-DA:11,4
-DA:13,1
-DA:14,1
-DA:15,1
-LF:6
-LH:6
-end_of_record
-SF:lib\utils\rsa_utils.dart
-DA:34,66
-DA:43,2
-DA:44,6
-DA:45,6
-DA:46,6
-DA:48,2
-DA:58,2
-DA:59,2
-DA:60,6
-DA:61,6
-DA:63,4
-DA:78,1
-DA:79,3
-DA:81,2
-DA:83,3
-DA:85,2
-DA:86,0
-DA:87,0
-DA:93,2
-DA:95,3
-DA:97,3
-DA:98,3
-DA:100,1
-DA:115,1
-DA:116,1
-DA:117,1
-DA:118,2
-DA:119,2
-DA:121,1
-DA:122,3
-DA:123,3
-DA:125,2
-DA:127,1
-DA:128,1
-DA:129,1
-DA:130,2
-DA:151,2
-DA:152,2
-DA:153,4
-DA:154,6
-DA:155,6
-DA:156,6
-DA:157,6
-DA:158,6
-DA:159,14
-DA:160,14
-DA:161,10
-DA:163,4
-DA:184,1
-DA:185,3
-DA:186,3
-DA:187,3
-DA:188,3
-DA:189,3
-DA:191,1
-DA:195,1
-DA:196,1
-DA:197,2
-DA:201,2
-DA:202,0
-DA:203,0
-DA:215,0
-DA:217,0
-DA:220,0
-DA:222,0
-DA:223,0
-DA:231,0
-DA:237,2
-DA:238,2
-DA:239,4
-DA:240,2
-DA:245,2
-DA:246,12
-DA:248,2
-DA:250,6
-DA:253,0
-DA:254,0
-DA:257,1
-DA:258,1
-DA:259,2
-DA:261,2
-LF:81
-LH:69
-end_of_record
-SF:lib\model\tokens\totp_token.dart
-DA:19,1
-DA:20,1
-DA:21,1
-DA:22,2
-DA:23,1
-DA:24,2
-DA:25,1
-DA:29,1
-DA:43,1
-DA:44,2
-DA:46,1
-DA:61,1
-DA:62,0
-DA:63,0
-DA:64,0
-DA:65,0
-DA:66,0
-DA:67,0
-DA:68,0
-DA:69,0
-DA:70,0
-DA:71,0
-DA:72,0
-DA:73,1
-DA:77,0
-DA:79,0
-DA:82,1
-DA:83,2
-DA:84,3
-DA:85,3
-DA:88,1
-DA:89,1
-DA:90,1
-DA:91,1
-DA:92,2
-DA:93,1
-DA:94,1
-DA:95,2
-DA:96,1
-DA:97,1
-DA:98,1
-DA:101,0
-DA:106,2
-DA:108,0
-DA:109,0
-DA:110,0
-DA:113,0
-DA:114,0
-DA:115,0
-DA:118,2
-LF:50
-LH:30
-end_of_record
-SF:lib\model\tokens\totp_token.g.dart
-DA:9,2
-DA:10,1
-DA:11,1
-DA:12,1
-DA:13,1
-DA:14,2
-DA:15,1
-DA:16,1
-DA:17,1
-DA:18,1
-DA:19,1
-DA:20,1
-DA:21,1
-DA:22,1
-DA:25,2
-DA:26,1
-DA:27,1
-DA:28,1
-DA:29,1
-DA:30,1
-DA:31,1
-DA:32,1
-DA:33,1
-DA:34,1
-DA:35,2
-DA:36,1
-DA:37,1
-DA:38,1
-LF:28
-LH:28
-end_of_record
-SF:lib\repo\preference_settings_repository.dart
+SF:lib\views\main_view\main_view_widgets\token_widgets\push_token_widgets\rollout_failed_widget.dart
+DA:14,0
+DA:16,0
+DA:18,0
DA:19,0
DA:20,0
+DA:22,0
DA:23,0
DA:25,0
DA:26,0
DA:27,0
DA:28,0
-DA:29,0
-DA:31,0
-DA:32,0
DA:33,0
-DA:34,0
-DA:44,0
-DA:47,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+DA:42,0
DA:49,0
DA:50,0
DA:51,0
DA:52,0
DA:53,0
DA:54,0
+DA:55,0
DA:56,0
-DA:57,0
-DA:59,0
-DA:60,0
-DA:61,0
-LF:25
+DA:69,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:75,0
+DA:76,0
+DA:78,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:88,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:93,0
+DA:94,0
+LF:46
LH:0
end_of_record
-SF:lib\repo\preference_token_folder_repository.dart
-DA:12,0
-DA:14,0
+SF:lib\views\main_view\main_view_widgets\token_widgets\push_token_widgets\rollout_widget.dart
+DA:8,0
+DA:10,0
+DA:11,0
+DA:13,0
+DA:15,0
+DA:16,0
DA:17,0
+LF:7
+LH:0
+end_of_record
+SF:lib\widgets\press_button.dart
+DA:9,0
+DA:11,0
+DA:12,0
DA:18,0
DA:19,0
DA:20,0
+DA:21,0
DA:23,0
DA:24,0
-DA:28,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:34,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+LF:17
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\token_widget_slideable.dart
+DA:13,0
+DA:21,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:29,0
+DA:30,0
DA:31,0
-DA:32,0
DA:33,0
-DA:34,0
DA:36,0
-LF:14
+LF:11
LH:0
end_of_record
-SF:lib\utils\logger.dart
+SF:lib\views\main_view\main_view_widgets\token_widgets\totp_token_widgets\totp_token_widget.dart
+DA:15,0
DA:22,0
-DA:27,0
+DA:24,0
+DA:25,0
+DA:26,0
DA:28,0
-DA:29,15
-DA:30,5
-DA:38,5
-DA:40,5
-DA:41,5
+LF:6
+LH:0
+end_of_record
+SF:lib\views\main_view\main_view_widgets\token_widgets\totp_token_widgets\totp_token_widget_tile.dart
+DA:20,0
+DA:22,0
+DA:23,0
+DA:31,0
+DA:32,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:41,0
+DA:42,0
DA:46,0
-DA:47,0
DA:48,0
DA:49,0
DA:51,0
+DA:53,0
DA:54,0
DA:55,0
DA:56,0
-DA:57,0
+DA:59,0
+DA:61,0
+DA:62,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:69,0
DA:70,0
DA:71,0
-DA:72,0
DA:73,0
DA:74,0
-DA:75,0
-DA:76,5
+DA:77,0
DA:78,0
DA:81,0
-DA:82,0
DA:83,0
-DA:88,5
-DA:93,0
-DA:99,15
-DA:100,5
-DA:101,15
+DA:84,0
+DA:87,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:92,0
+DA:96,0
+DA:98,0
+DA:99,0
+DA:100,0
+DA:101,0
+DA:102,0
+DA:103,0
+DA:105,0
DA:106,0
+DA:107,0
DA:108,0
DA:110,0
-DA:115,5
-DA:116,10
-DA:117,10
+DA:111,0
+DA:112,0
+DA:113,0
+DA:114,0
+DA:115,0
+DA:117,0
DA:118,0
-DA:120,5
-DA:123,1
-DA:124,2
-DA:125,2
+DA:123,0
+DA:124,0
+DA:125,0
DA:126,0
-DA:128,1
+DA:127,0
+DA:128,0
+DA:129,0
DA:131,0
DA:132,0
DA:133,0
-DA:134,0
DA:135,0
+DA:136,0
DA:137,0
DA:138,0
DA:139,0
+DA:141,0
DA:142,0
DA:143,0
-DA:144,0
-DA:145,0
+DA:147,0
DA:148,0
DA:149,0
+DA:150,0
DA:151,0
-DA:153,0
-DA:157,0
-DA:158,0
-DA:161,0
-DA:162,0
-DA:163,0
-DA:164,0
-DA:170,0
-DA:171,0
-DA:172,0
-DA:173,0
-DA:174,0
-DA:175,0
-DA:179,0
-DA:180,0
-DA:181,0
-DA:182,0
-DA:183,0
-DA:184,0
-DA:187,0
-DA:189,0
-DA:195,0
-DA:196,0
-DA:199,0
-DA:200,0
-DA:201,0
-DA:202,0
-DA:203,0
-DA:204,0
-DA:205,0
-DA:206,0
-DA:216,5
-DA:217,5
-DA:218,5
-DA:219,5
-DA:220,5
-DA:223,5
-DA:224,10
-DA:225,5
-DA:228,0
-DA:229,0
-DA:230,0
-DA:231,0
-DA:232,0
-DA:233,0
-DA:234,0
-DA:235,0
-DA:238,0
-DA:239,0
-DA:242,0
-DA:246,5
-DA:247,10
-DA:250,5
-DA:251,10
-DA:252,0
-DA:255,5
-DA:256,10
-DA:257,0
-DA:258,0
-DA:261,5
-DA:262,0
-DA:263,0
-DA:268,10
-DA:269,5
-DA:271,0
-DA:272,0
-DA:273,0
-DA:274,0
-DA:276,5
-DA:279,5
-DA:284,5
-DA:286,10
-DA:289,5
-DA:291,10
-DA:294,0
-DA:296,0
-DA:301,0
-DA:302,0
-DA:303,0
-DA:304,0
-DA:305,0
-DA:306,0
-DA:307,0
-DA:309,0
-DA:310,0
-DA:311,0
-DA:312,0
-DA:313,0
-DA:322,0
-DA:323,0
-DA:324,0
-DA:325,0
-DA:326,0
-DA:327,0
-DA:334,0
-DA:335,0
-DA:336,0
-DA:337,0
-DA:342,5
-DA:343,15
-DA:344,10
-DA:345,8
-DA:346,5
-DA:348,5
-DA:350,15
-DA:351,5
-DA:352,25
-DA:353,25
-DA:354,15
-DA:359,0
-DA:360,0
-DA:361,0
-DA:362,0
-DA:363,0
-DA:364,0
-DA:365,0
-DA:366,0
-DA:367,0
-DA:368,0
-DA:369,0
-DA:370,0
-DA:371,0
-DA:372,0
-DA:373,0
-DA:374,0
-DA:375,0
-DA:376,0
-DA:377,0
-DA:378,0
-DA:379,0
-DA:380,0
-DA:381,0
-DA:382,0
-DA:383,0
-DA:384,0
-DA:385,0
-DA:386,0
-DA:387,0
-DA:388,0
-DA:389,0
-DA:390,0
-DA:391,0
-DA:392,0
-DA:395,0
-DA:396,0
-DA:397,0
-DA:398,0
-DA:399,0
-DA:400,0
-DA:401,0
-DA:402,0
-DA:403,0
-DA:404,0
-DA:405,0
-DA:406,0
-DA:408,0
-LF:217
-LH:52
+LF:84
+LH:0
end_of_record
-SF:lib\repo\secure_token_repository.dart
-DA:33,32
-DA:36,0
+SF:lib\views\main_view\main_view_widgets\token_widgets\totp_token_widgets\actions\edit_totp_token_action.dart
+DA:19,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:32,0
+DA:34,0
+DA:35,0
+DA:38,0
+DA:39,0
DA:40,0
-DA:53,0
+DA:43,0
+DA:45,0
+DA:46,0
+DA:54,0
DA:55,0
DA:56,0
DA:57,0
DA:58,0
-DA:61,0
+DA:60,0
DA:62,0
DA:63,0
DA:65,0
+DA:66,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:77,0
+DA:78,0
+DA:81,0
+DA:82,0
+DA:83,0
+DA:87,0
+DA:89,0
+DA:90,0
+DA:91,0
+DA:94,0
+DA:95,0
+DA:97,0
+DA:101,0
+DA:102,0
+DA:104,0
+DA:105,0
+DA:106,0
+DA:107,0
+DA:112,0
+DA:114,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:122,0
+DA:123,0
+DA:124,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:132,0
+DA:133,0
+DA:134,0
+DA:138,0
+DA:139,0
+LF:64
+LH:0
+end_of_record
+SF:lib\views\push_token_view\widgets\push_tokens_view_list.dart
+DA:16,17
+DA:18,0
+DA:19,0
+DA:28,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:49,0
+DA:50,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:66,0
+DA:67,0
+DA:68,0
+DA:69,0
DA:70,0
+DA:71,0
DA:72,0
-DA:82,0
+DA:73,0
+DA:80,0
+DA:81,0
DA:84,0
+DA:87,0
+DA:89,0
+LF:37
+LH:1
+end_of_record
+SF:lib\views\qr_scanner_view\qr_scanner_view_widgets\qr_scanner_widget.dart
+DA:13,0
+DA:15,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:41,0
+DA:44,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:49,0
+DA:50,0
+DA:52,0
+DA:55,0
+DA:58,0
+DA:59,0
+DA:66,17
+DA:68,0
+DA:69,0
+DA:77,0
+DA:79,0
+DA:80,0
+DA:83,0
+DA:85,0
DA:86,0
-DA:88,0
DA:89,0
DA:90,0
+DA:91,0
+DA:92,0
+DA:93,0
+DA:94,0
+DA:95,0
DA:96,0
DA:97,0
-DA:98,0
-DA:101,0
DA:102,0
+DA:104,0
+DA:106,0
+DA:107,0
+DA:109,0
DA:111,0
DA:112,0
-DA:113,0
+DA:116,0
+DA:117,0
+DA:118,0
+DA:119,0
+DA:121,0
+DA:124,0
DA:125,0
-DA:126,0
-DA:128,0
+DA:129,0
+DA:130,0
DA:131,0
+DA:134,0
DA:135,0
-DA:137,0
+DA:136,0
DA:138,0
DA:139,0
DA:140,0
+DA:141,0
+DA:142,0
DA:143,0
DA:144,0
-DA:145,0
-DA:151,0
-DA:153,0
-DA:155,0
-DA:158,0
-DA:168,0
-DA:170,0
-DA:175,0
-DA:177,0
-LF:48
+DA:149,0
+DA:150,0
+LF:70
LH:1
end_of_record
-SF:lib\state_notifiers\app_state_notifier.dart
-DA:6,2
-DA:8,1
-DA:9,1
-LF:3
-LH:3
-end_of_record
-SF:lib\state_notifiers\deeplink_notifier.dart
-DA:13,0
-DA:14,0
-DA:15,0
+SF:lib\views\qr_scanner_view\qr_scanner_view_widgets\qr_code_scanner_overlay.dart
+DA:11,0
DA:18,0
-DA:20,0
DA:21,0
-DA:26,0
-DA:30,0
-DA:31,0
-DA:32,0
-DA:34,0
-DA:35,0
-DA:36,0
-DA:37,0
-DA:42,0
-DA:45,0
-DA:47,0
-DA:49,0
-DA:50,0
-DA:51,0
-DA:52,0
-DA:54,0
-DA:55,0
-DA:56,0
-DA:57,0
-LF:25
-LH:0
-end_of_record
-SF:lib\state_notifiers\push_request_notifier.dart
-DA:41,1
-DA:48,0
-DA:50,1
-DA:51,2
-DA:55,1
-DA:56,2
-DA:57,1
-DA:58,1
-DA:59,1
-DA:61,0
-DA:64,1
-DA:68,1
-DA:69,2
-DA:70,1
-DA:71,1
-DA:72,1
-DA:74,0
-DA:77,1
-DA:81,0
-DA:83,1
-DA:84,1
-DA:86,3
-DA:87,2
-DA:90,3
-DA:91,2
-DA:92,1
-DA:94,3
-DA:95,2
-DA:105,1
-DA:106,1
-DA:107,1
-DA:110,2
-DA:111,1
-DA:114,4
-DA:115,2
-DA:116,0
-DA:119,0
-LF:37
-LH:31
-end_of_record
-SF:lib\utils\firebase_utils.dart
-DA:15,1
-DA:17,1
-DA:18,1
DA:22,0
+DA:23,0
+DA:24,0
+DA:26,0
DA:27,0
+DA:28,0
+DA:29,0
DA:30,0
DA:31,0
+DA:32,0
DA:34,0
-DA:39,0
+DA:38,0
DA:40,0
-DA:41,0
DA:42,0
-DA:43,0
-DA:48,0
+DA:46,0
+DA:47,0
DA:49,0
DA:50,0
-DA:51,0
DA:53,0
+DA:55,0
DA:56,0
DA:57,0
DA:60,0
-DA:62,0
-DA:63,0
+DA:61,0
+DA:64,0
DA:65,0
-DA:66,0
+DA:68,0
DA:69,0
-DA:70,0
-DA:71,0
DA:72,0
-DA:76,0
+DA:73,0
+DA:77,0
DA:78,0
DA:79,0
DA:80,0
-DA:81,0
-DA:85,0
-DA:87,0
+DA:82,0
+DA:83,0
+DA:84,0
DA:88,0
DA:89,0
+DA:90,0
+DA:91,0
DA:93,0
+DA:94,0
+DA:95,0
DA:96,0
-DA:97,0
DA:98,0
-DA:101,0
-DA:103,0
-DA:104,0
+DA:100,0
DA:105,0
-DA:109,0
-DA:118,0
-DA:121,0
+DA:106,0
+DA:107,0
+DA:108,0
+DA:110,0
+DA:111,0
+DA:112,0
+DA:113,0
+DA:115,0
+DA:117,0
DA:122,0
DA:123,0
DA:124,0
DA:125,0
-DA:126,0
-DA:131,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:130,0
DA:132,0
-DA:137,0
+DA:134,0
DA:139,0
+DA:140,0
+DA:141,0
+DA:142,0
+DA:144,0
DA:145,0
-LF:59
-LH:3
+DA:146,0
+DA:147,0
+DA:149,0
+DA:151,0
+DA:156,0
+DA:158,0
+DA:159,0
+DA:160,0
+DA:161,0
+DA:162,0
+LF:86
+LH:0
end_of_record
-SF:lib\utils\network_utils.dart
-DA:31,48
+SF:lib\views\settings_view\settings_groups\import_export_tokens_widgets\dialogs\export_tokens_to_file_dialog.dart
+DA:17,0
+DA:19,0
+DA:20,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:35,0
DA:36,0
+DA:37,0
DA:38,0
DA:39,0
DA:40,0
DA:41,0
DA:42,0
+DA:43,0
DA:44,0
-DA:47,0
-DA:48,0
-DA:51,0
-DA:56,0
-DA:57,0
-DA:58,0
-DA:60,0
+DA:45,0
+DA:46,0
+DA:50,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:55,0
DA:61,0
DA:62,0
DA:63,0
DA:64,0
+DA:65,0
DA:66,0
-DA:70,0
-DA:71,0
-DA:72,0
+DA:67,0
+DA:68,0
+DA:69,0
DA:73,0
-DA:74,0
+DA:75,0
DA:76,0
-DA:80,0
-DA:81,0
-DA:82,0
+DA:77,0
+DA:78,0
DA:85,0
DA:86,0
-DA:89,0
-DA:92,0
+DA:88,0
+DA:96,0
DA:97,0
DA:98,0
DA:99,0
DA:100,0
-DA:101,0
DA:102,0
DA:103,0
+DA:104,0
DA:105,0
+DA:108,0
DA:109,0
DA:110,0
-DA:111,0
-DA:112,0
DA:113,0
DA:115,0
DA:117,0
-DA:119,0
DA:120,0
DA:121,0
-DA:125,0
-DA:127,0
+DA:123,0
+DA:126,0
DA:128,0
DA:129,0
DA:130,0
-DA:131,0
DA:132,0
+DA:135,0
DA:136,0
-DA:137,0
-DA:140,0
-DA:144,0
-LF:62
-LH:1
-end_of_record
-SF:lib\utils\push_provider.dart
-DA:54,0
-DA:58,0
-DA:59,0
-DA:60,0
-DA:61,0
-DA:62,0
-DA:63,0
-DA:64,0
-DA:70,0
-DA:76,0
-DA:79,0
-DA:82,0
-DA:87,0
-DA:95,0
-DA:97,0
-DA:99,0
-DA:103,0
-DA:104,0
-DA:105,0
-DA:107,0
-DA:108,0
-DA:109,0
-DA:110,0
-DA:111,0
-DA:113,0
-DA:114,0
-DA:120,0
-DA:121,0
-DA:122,0
-DA:124,0
-DA:125,0
-DA:126,0
-DA:127,0
-DA:129,0
-DA:130,0
-DA:138,0
-DA:139,0
-DA:140,0
DA:141,0
+DA:142,0
DA:143,0
-DA:144,0
DA:145,0
DA:146,0
-DA:148,0
+DA:149,0
DA:150,0
-DA:152,0
DA:155,0
DA:156,0
-DA:159,0
-DA:161,0
-DA:167,0
-DA:168,0
-DA:169,0
-DA:170,0
-DA:172,0
-DA:173,0
-DA:174,0
-DA:175,0
-DA:177,0
-DA:179,0
-DA:181,0
-DA:184,0
-DA:185,0
-DA:188,0
-DA:189,0
-DA:192,0
-DA:193,0
-DA:194,0
-DA:195,0
-DA:197,0
-DA:200,0
-DA:201,0
-DA:202,0
-DA:203,0
-DA:206,0
-DA:208,0
-DA:209,0
-DA:210,0
-DA:211,0
-DA:215,0
-DA:216,0
-DA:217,0
-DA:218,0
-DA:225,0
-DA:226,0
-DA:227,0
-DA:228,0
-DA:229,0
-DA:233,0
-DA:236,0
-DA:237,0
-DA:238,0
-DA:243,0
-DA:244,0
-DA:245,0
-DA:247,0
-DA:248,0
-DA:255,0
-DA:256,0
-DA:258,0
-DA:260,0
-DA:261,0
-DA:262,0
-DA:264,0
-DA:267,0
-DA:268,0
-DA:275,0
-DA:276,0
-DA:278,0
-DA:279,0
-DA:282,0
-DA:283,0
-DA:285,0
-DA:286,0
-DA:287,0
-DA:291,0
-DA:292,0
-DA:293,0
-DA:297,0
-DA:298,0
-DA:301,0
-DA:307,0
-DA:308,0
-DA:310,0
-DA:312,0
-DA:314,0
-DA:315,0
-DA:316,0
-DA:321,0
-DA:334,0
-DA:340,0
-DA:344,0
-DA:353,0
-DA:355,0
-DA:358,0
-DA:363,0
-DA:364,0
-DA:365,0
-DA:366,0
-DA:368,0
-DA:369,0
-DA:371,0
-DA:377,0
-LF:143
+DA:157,0
+DA:158,0
+LF:77
+LH:0
+end_of_record
+SF:lib\views\settings_view\settings_groups\import_export_tokens_widgets\dialogs\select_export_type_dialog.dart
+DA:12,17
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:39,0
+DA:40,0
+DA:42,0
+DA:43,0
+DA:46,0
+DA:49,0
+DA:50,0
+DA:52,0
+DA:54,0
+DA:57,0
+LF:26
+LH:1
+end_of_record
+SF:lib\views\settings_view\settings_view_widgets\settings_list_tile_button.dart
+DA:9,0
+DA:11,0
+DA:12,0
+DA:13,0
+DA:14,0
+DA:16,0
+DA:18,0
+DA:20,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:29,0
+DA:31,0
+LF:14
+LH:0
+end_of_record
+SF:lib\views\settings_view\settings_groups\import_export_tokens_widgets\dialogs\select_tokens_dialog.dart
+DA:14,0
+DA:16,0
+DA:17,0
+DA:22,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:36,0
+DA:38,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:47,0
+DA:49,0
+DA:53,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:60,0
+DA:62,0
+DA:64,0
+DA:69,0
+DA:70,0
+DA:71,0
+DA:72,0
+DA:73,0
+DA:74,0
+DA:76,0
+DA:77,0
+DA:78,0
+DA:79,0
+DA:82,0
+DA:83,0
+DA:84,0
+DA:87,0
+DA:88,0
+DA:89,0
+DA:91,0
+DA:92,0
+DA:97,0
+DA:109,0
+DA:110,0
+DA:111,0
+DA:112,0
+DA:114,0
+DA:115,0
+DA:116,0
+DA:117,0
+DA:118,0
+DA:121,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:130,0
+DA:131,0
+DA:132,0
+DA:133,0
+DA:134,0
+DA:135,0
+DA:137,0
+LF:70
LH:0
end_of_record
-SF:lib\state_notifiers\settings_notifier.dart
-DA:16,1
-DA:20,1
-DA:21,1
-DA:23,1
-DA:24,3
-DA:25,3
-DA:26,3
-DA:30,1
-DA:31,3
-DA:32,3
-DA:35,1
-DA:36,2
-DA:37,3
-DA:38,3
-DA:39,1
+SF:lib\views\settings_view\settings_groups\import_export_tokens_widgets\dialogs\show_qr_code_dialog.dart
+DA:18,0
+DA:20,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
DA:42,0
DA:43,0
DA:44,0
DA:45,0
+DA:47,0
DA:48,0
DA:49,0
-DA:50,0
-DA:51,0
-DA:54,0
DA:55,0
DA:56,0
-DA:57,0
-DA:60,1
-DA:61,2
-DA:62,3
-DA:63,1
-DA:66,1
-DA:67,2
-DA:68,3
-DA:69,1
+DA:58,0
+DA:59,0
+DA:60,0
+DA:65,0
+DA:66,0
+DA:67,0
+DA:68,0
DA:72,0
DA:73,0
DA:74,0
-DA:75,0
-DA:78,0
+DA:77,0
DA:79,0
DA:80,0
DA:81,0
-DA:84,1
-DA:85,2
-DA:86,3
-DA:87,1
-DA:90,0
-DA:91,0
-DA:92,0
+DA:82,0
+DA:84,0
+DA:85,0
+DA:86,0
+DA:87,0
+DA:88,0
DA:93,0
-DA:96,1
-DA:97,2
-DA:98,3
-DA:99,1
-DA:102,1
-DA:103,2
-DA:104,2
-DA:105,3
-DA:106,1
-DA:109,1
-DA:110,2
-DA:111,3
-DA:112,1
-LF:64
-LH:40
+LF:46
+LH:0
end_of_record
-SF:lib\state_notifiers\token_folder_notifier.dart
-DA:11,1
-DA:13,1
-DA:14,1
-DA:17,8
-DA:19,1
-DA:20,3
-DA:21,2
-DA:22,1
+SF:lib\views\settings_view\settings_groups\settings_group_error_log.dart
+DA:8,17
+DA:10,0
+DA:11,0
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:22,0
DA:23,0
-DA:28,1
-DA:29,2
-DA:30,1
-DA:31,2
-DA:34,1
-DA:35,2
-DA:36,1
-DA:37,2
-DA:40,1
-DA:41,3
-DA:42,1
-DA:43,2
-DA:46,1
-DA:47,2
-DA:48,1
-DA:49,2
+DA:24,0
+DA:28,0
+DA:30,0
+LF:14
+LH:1
+end_of_record
+SF:lib\views\settings_view\settings_view_widgets\logging_menu.dart
+DA:12,17
+DA:14,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:20,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:26,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:37,0
+DA:39,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:50,0
+DA:54,0
+LF:22
+LH:1
+end_of_record
+SF:lib\views\settings_view\settings_view_widgets\settings_groups.dart
+DA:29,0
+DA:34,0
+DA:36,0
+DA:37,0
+DA:39,0
+DA:40,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:49,0
+DA:51,0
+LF:11
+LH:0
+end_of_record
+SF:lib\views\settings_view\settings_groups\settings_group_general.dart
+DA:14,17
+DA:16,0
+DA:18,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:27,0
+DA:28,0
+DA:29,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:50,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:59,0
+DA:61,0
+LF:28
+LH:1
+end_of_record
+SF:lib\views\settings_view\settings_groups\settings_group_import_export_tokens.dart
+DA:12,17
+DA:14,0
+DA:15,0
+DA:19,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:35,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:41,0
+DA:42,0
+DA:43,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:61,0
+LF:23
+LH:1
+end_of_record
+SF:lib\views\settings_view\settings_groups\settings_group_language.dart
+DA:9,17
+DA:11,0
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:20,0
+DA:21,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:28,0
+DA:29,0
+DA:30,0
+DA:31,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:40,0
+DA:41,0
+DA:46,0
+DA:47,0
LF:25
-LH:24
-end_of_record
-SF:lib\state_notifiers\token_notifier.dart
-DA:45,1
-DA:58,1
-DA:59,1
-DA:60,1
-DA:62,1
-DA:65,1
-DA:66,3
-DA:67,2
-DA:68,1
-DA:69,0
-DA:70,0
-DA:73,0
-DA:75,2
-DA:76,4
-DA:81,1
-DA:82,3
-DA:83,2
-DA:84,3
-DA:88,1
-DA:91,3
-DA:92,2
-DA:93,1
-DA:94,1
-DA:95,1
-DA:98,4
-DA:99,2
-DA:100,2
-DA:101,1
-DA:110,1
-DA:111,1
-DA:114,2
-DA:118,5
-DA:119,2
-DA:120,3
-DA:124,1
-DA:125,6
-DA:128,1
-DA:129,3
-DA:130,3
-DA:131,2
-DA:134,1
-DA:135,3
-DA:136,2
-DA:139,1
-DA:140,3
-DA:141,2
-DA:145,1
-DA:146,3
-DA:147,1
-DA:150,0
-DA:151,0
-DA:152,0
-DA:155,0
-DA:156,0
-DA:159,0
-DA:162,0
-DA:164,0
-DA:167,1
-DA:170,1
-DA:177,2
-DA:179,3
-DA:181,0
-DA:182,0
-DA:184,0
-DA:185,0
-DA:186,0
-DA:187,0
-DA:188,0
-DA:194,1
-DA:195,0
-DA:196,0
-DA:197,0
-DA:201,1
-DA:202,0
-DA:205,1
-DA:208,0
-DA:210,0
-DA:211,0
-DA:216,1
-DA:217,1
-DA:218,9
-DA:219,5
-DA:221,0
-DA:224,1
-DA:225,2
-DA:226,1
-DA:227,1
-DA:228,1
-DA:229,1
-DA:230,1
-DA:233,1
-DA:234,0
-DA:236,1
-DA:237,0
-DA:238,5
-DA:241,0
-DA:244,0
-DA:248,1
-DA:250,2
-DA:251,0
-DA:252,0
-DA:253,0
-DA:259,1
-DA:260,1
-DA:262,4
-DA:266,1
-DA:267,3
-DA:268,8
-DA:271,0
-DA:274,1
-DA:275,1
-DA:277,4
-DA:281,1
-DA:282,2
-DA:283,2
-DA:284,3
-DA:285,1
-DA:286,2
-DA:287,2
-DA:288,2
-DA:289,2
-DA:290,4
-DA:294,2
-DA:295,0
-DA:296,0
-DA:297,0
-DA:298,0
-DA:302,0
-DA:305,1
-DA:306,0
-DA:309,1
-DA:310,2
-DA:312,2
-DA:313,2
-DA:314,2
-DA:315,1
-DA:316,4
-DA:317,1
-DA:319,0
-DA:320,0
-DA:325,2
-DA:328,2
-DA:329,1
-DA:330,1
-DA:331,1
-DA:332,1
-DA:333,1
-DA:334,2
-DA:335,3
-DA:339,2
-DA:340,2
-DA:342,1
-DA:343,1
-DA:344,0
-DA:345,0
-DA:346,0
-DA:347,0
-DA:350,1
-DA:351,1
-DA:352,1
-DA:356,0
-DA:358,0
-DA:362,0
-DA:363,0
-DA:364,0
-DA:366,0
-DA:367,0
-DA:368,0
-DA:371,0
-DA:375,0
-DA:376,0
-DA:377,0
-DA:378,0
-DA:381,0
-DA:382,0
-DA:383,0
-DA:384,0
-DA:385,0
-DA:388,0
-DA:390,0
-DA:391,0
-DA:392,0
-DA:396,0
-DA:397,0
-DA:403,1
-DA:404,2
-DA:406,4
-DA:407,1
-DA:409,1
-DA:411,2
-DA:412,0
-DA:413,0
-LF:192
-LH:120
+LH:1
end_of_record
-SF:lib\utils\qr_parser.dart
-DA:27,17
-DA:30,1
-DA:31,1
-DA:32,1
-DA:40,2
-DA:41,1
-DA:44,2
-DA:48,1
-DA:49,2
-DA:50,2
-DA:51,2
-DA:52,1
-DA:53,2
+SF:lib\views\settings_view\settings_groups\settings_group_push_token.dart
+DA:13,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:22,0
+DA:23,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:29,0
+DA:30,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:40,0
+DA:44,0
+DA:45,0
+DA:51,0
+DA:52,0
+DA:53,0
DA:54,0
-DA:57,1
-DA:60,1
+DA:55,0
+DA:56,0
+DA:57,0
+DA:60,0
+DA:61,0
+DA:63,0
DA:64,0
+DA:65,0
DA:77,0
-DA:79,0
+DA:78,0
+DA:81,0
DA:82,0
-DA:85,0
+DA:83,0
+DA:86,0
+DA:87,0
+DA:88,0
DA:89,0
+DA:90,0
DA:91,0
-DA:93,0
-DA:94,0
-DA:96,0
-DA:100,0
+DA:92,0
+DA:97,0
+DA:98,0
DA:101,0
+DA:102,0
+DA:103,0
DA:104,0
-DA:105,0
-DA:108,0
-DA:109,0
-DA:110,0
-DA:112,0
DA:113,0
-DA:115,0
+DA:114,0
DA:116,0
+DA:117,0
DA:118,0
DA:119,0
DA:120,0
-DA:123,0
-DA:125,0
-DA:126,0
-DA:127,0
-DA:130,0
-DA:131,0
-DA:133,0
-DA:136,0
-DA:137,0
-DA:145,1
-DA:148,1
-DA:151,2
-DA:155,3
-DA:156,3
-DA:158,1
-DA:163,1
-DA:164,1
-DA:165,1
-DA:168,3
-DA:169,0
-DA:172,2
-DA:173,0
-DA:176,3
-DA:178,2
-DA:179,2
-DA:180,2
-DA:181,1
-DA:184,1
-DA:188,1
-DA:191,2
-DA:193,2
-DA:194,1
-DA:197,1
-DA:201,1
-DA:203,1
-DA:206,2
-DA:207,1
-DA:213,3
-DA:214,0
-DA:216,1
-DA:217,1
-DA:218,1
-DA:221,2
-DA:225,1
-DA:227,1
-DA:229,2
-DA:231,2
-DA:234,1
-DA:240,2
-DA:241,1
-DA:242,1
-DA:245,1
-DA:250,4
-DA:252,2
-DA:254,1
-DA:256,2
-DA:258,1
-DA:261,1
-DA:263,0
-DA:264,0
-DA:265,0
-DA:269,0
-DA:270,0
-DA:271,0
-DA:274,0
-DA:278,0
-DA:279,0
-DA:280,0
-DA:283,0
-DA:287,0
-DA:288,0
-DA:289,0
-DA:292,0
-DA:301,1
-DA:304,2
-DA:305,1
-DA:308,1
-DA:309,1
-DA:310,1
-DA:311,1
-DA:314,1
-DA:316,0
-DA:323,1
-DA:325,2
-DA:328,1
-DA:329,1
-DA:336,1
-DA:337,6
-LF:128
-LH:75
+DA:122,0
+DA:123,0
+DA:124,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:130,0
+DA:131,0
+DA:133,0
+LF:65
+LH:0
+end_of_record
+SF:lib\views\settings_view\settings_view_widgets\update_firebase_token_dialog.dart
+DA:33,17
+DA:35,0
+DA:36,0
+DA:45,0
+DA:47,0
+DA:48,0
+DA:51,0
+DA:53,0
+DA:55,0
+DA:56,0
+DA:57,0
+DA:58,0
+DA:59,0
+DA:60,0
+DA:66,0
+DA:67,0
+DA:71,0
+DA:73,0
+DA:79,0
+DA:80,0
+DA:81,0
+DA:82,0
+DA:85,0
+DA:87,0
+DA:88,0
+DA:89,0
+DA:91,0
+DA:92,0
+DA:96,0
+DA:97,0
+DA:98,0
+DA:101,0
+DA:102,0
+DA:103,0
+DA:107,0
+DA:108,0
+DA:109,0
+DA:110,0
+DA:113,0
+DA:115,0
+LF:40
+LH:1
end_of_record
-SF:lib\utils\customizations.dart
+SF:lib\views\settings_view\settings_groups\settings_group_theme.dart
+DA:9,17
+DA:11,0
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:16,0
+DA:17,0
+DA:18,0
+DA:23,0
DA:25,0
DA:26,0
-LF:2
-LH:0
+DA:27,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:38,0
+DA:40,0
+DA:41,0
+DA:42,0
+DA:45,0
+DA:46,0
+DA:47,0
+DA:48,0
+DA:51,0
+DA:53,0
+DA:54,0
+DA:55,0
+LF:29
+LH:1
end_of_record
-SF:lib\utils\view_utils.dart
-DA:7,0
+SF:lib\views\settings_view\settings_view_widgets\dialogs\ask_log_sended_dialog.dart
+DA:9,17
DA:11,0
-DA:12,0
+DA:13,0
+DA:14,0
DA:15,0
+DA:19,0
+DA:20,0
+DA:21,0
+DA:23,0
+DA:24,0
+DA:26,0
+DA:27,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:40,0
+DA:42,0
+DA:43,0
+DA:44,0
+DA:45,0
+DA:47,0
+DA:48,0
+LF:23
+LH:1
+end_of_record
+SF:lib\views\settings_view\settings_view_widgets\errorlog_buttons\delete_errorlog_button.dart
+DA:8,17
+DA:10,0
+DA:11,0
+DA:12,0
+DA:13,0
+DA:16,0
+DA:17,0
+DA:18,0
+LF:8
+LH:1
+end_of_record
+SF:lib\views\settings_view\settings_view_widgets\errorlog_buttons\errorlog_button.dart
+DA:6,0
+DA:8,0
+DA:9,0
+DA:10,0
+DA:12,0
+DA:14,0
DA:16,0
+DA:17,0
+DA:18,0
+DA:19,0
+LF:10
+LH:0
+end_of_record
+SF:lib\views\settings_view\settings_view_widgets\errorlog_buttons\send_errorlog_button.dart
+DA:9,17
+DA:11,0
+DA:12,0
+DA:13,0
+DA:14,0
+DA:18,0
+DA:19,0
DA:20,0
DA:23,0
+DA:26,0
+DA:29,0
+LF:11
+LH:1
+end_of_record
+SF:lib\views\settings_view\settings_view_widgets\errorlog_buttons\show_errorlog_button.dart
+DA:10,17
+DA:12,0
+DA:13,0
+DA:14,0
+DA:15,0
+DA:19,0
+DA:20,0
+DA:21,0
DA:24,0
+DA:28,0
+DA:30,0
+DA:31,0
+DA:32,0
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:37,0
+DA:38,0
+DA:39,0
+DA:42,0
+DA:45,0
+DA:48,0
+DA:51,0
+DA:52,0
+DA:53,0
+DA:54,0
+DA:56,0
+DA:57,0
+DA:58,0
+LF:30
+LH:1
+end_of_record
+SF:lib\widgets\app_wrappers\single_touch_recognizer.dart
+DA:6,0
+DA:8,0
+DA:10,0
+DA:11,0
+DA:12,0
+DA:13,0
+DA:14,0
+DA:17,0
DA:25,0
-DA:27,0
DA:28,0
-LF:11
+DA:30,0
+DA:31,0
+DA:32,0
+DA:34,0
+DA:38,0
+DA:41,0
+DA:44,0
+DA:46,0
+DA:47,0
+LF:19
+LH:0
+end_of_record
+SF:lib\widgets\app_wrappers\state_observer.dart
+DA:10,0
+DA:12,0
+DA:14,0
+DA:15,0
+DA:17,0
+LF:5
LH:0
end_of_record
-SF:lib\widgets\two_step_dialog.dart
+SF:lib\widgets\dialog_widgets\push_request_dialog.dart
+DA:17,0
+DA:19,0
+DA:20,0
+DA:26,0
+DA:31,0
+DA:33,0
+DA:34,0
DA:36,0
+DA:37,0
+DA:38,0
DA:42,0
-DA:43,0
-DA:55,0
+DA:45,0
+DA:47,0
+DA:48,0
+DA:49,0
+DA:51,0
+DA:52,0
+DA:53,0
DA:57,0
-DA:58,0
+DA:59,0
DA:61,0
+DA:62,0
DA:63,0
-DA:65,0
+DA:64,0
DA:68,0
-DA:70,0
DA:71,0
DA:72,0
DA:73,0
+DA:74,0
DA:75,0
DA:77,0
-DA:78,0
+DA:81,0
DA:82,0
DA:83,0
-DA:84,0
DA:85,0
-DA:86,0
-DA:87,0
-DA:98,0
+DA:89,0
+DA:91,0
+DA:93,0
+DA:94,0
+DA:95,0
+DA:96,0
+DA:99,0
DA:100,0
-DA:103,0
-DA:105,0
+DA:102,0
DA:106,0
DA:107,0
-DA:111,0
-DA:112,0
+DA:108,0
+DA:109,0
DA:114,0
-DA:115,0
DA:116,0
-DA:121,0
-LF:35
-LH:0
-end_of_record
-SF:lib\utils\app_customizer.dart
-DA:13,0
-DA:33,16
-DA:64,16
-DA:120,0
-DA:139,0
+DA:122,0
+DA:123,0
+DA:125,0
+DA:126,0
+DA:127,0
+DA:128,0
+DA:129,0
+DA:132,0
+DA:133,0
+DA:134,0
+DA:136,0
DA:140,0
DA:141,0
DA:142,0
DA:143,0
-DA:144,0
-DA:145,0
-DA:146,0
DA:147,0
-DA:148,0
-DA:149,0
-DA:150,0
-DA:151,0
-DA:152,0
-DA:153,0
-DA:154,0
-DA:155,0
-DA:156,0
+DA:157,0
DA:159,0
DA:160,0
DA:161,0
@@ -3162,237 +11591,121 @@ DA:162,0
DA:163,0
DA:164,0
DA:165,0
-DA:166,0
-DA:167,0
-DA:168,0
DA:169,0
-DA:170,0
-DA:171,0
DA:172,0
DA:173,0
DA:174,0
DA:175,0
-DA:176,0
DA:179,0
DA:180,0
-DA:181,0
-DA:182,0
DA:183,0
-DA:184,0
DA:185,0
-DA:186,0
DA:187,0
DA:188,0
DA:189,0
DA:190,0
DA:191,0
-DA:192,0
DA:193,0
-DA:194,0
DA:195,0
DA:196,0
-DA:199,0
-DA:200,0
-DA:201,0
+DA:197,0
+DA:198,0
DA:202,0
-DA:203,0
DA:204,0
DA:205,0
DA:206,0
DA:207,0
-DA:208,0
-DA:209,0
-DA:210,0
-DA:211,0
-DA:212,0
-DA:213,0
-DA:214,0
-DA:215,0
-DA:258,0
-DA:265,0
-DA:266,0
-DA:268,0
-DA:269,0
-DA:271,0
-DA:273,0
-DA:274,0
-DA:277,0
-DA:281,0
-DA:290,0
-DA:291,0
-DA:292,0
-DA:293,0
-DA:294,0
-DA:295,0
-DA:296,0
-DA:299,0
-DA:301,0
-DA:303,0
-DA:304,0
-DA:305,0
-DA:306,0
-DA:307,0
-DA:308,0
-DA:309,0
-DA:312,0
-DA:313,0
-DA:314,0
-DA:315,0
-DA:316,0
-DA:317,0
-DA:318,0
-DA:319,0
-DA:324,0
-DA:325,0
-DA:327,0
-DA:328,0
-DA:329,0
-DA:330,0
-DA:331,0
-DA:332,0
-DA:333,0
-DA:334,0
-DA:335,0
-DA:336,0
-DA:337,0
-DA:338,0
-DA:339,0
-DA:340,0
-DA:342,0
-DA:343,0
-DA:344,0
-DA:345,0
-DA:346,0
-DA:347,0
-DA:350,0
-DA:351,0
-DA:352,0
-DA:353,0
-DA:354,0
-DA:357,0
-DA:358,0
-DA:359,0
-DA:361,0
-DA:362,0
-DA:363,0
-DA:364,0
-DA:365,0
-DA:367,0
-DA:368,0
-DA:369,0
-DA:370,0
-DA:371,0
-DA:372,0
-DA:373,0
-DA:375,0
-DA:376,0
-DA:377,0
-DA:378,0
-DA:379,0
-DA:380,0
-DA:382,0
-DA:383,0
-DA:384,0
-DA:387,0
-DA:388,0
-DA:393,0
-DA:394,0
-DA:395,0
-DA:398,0
-DA:399,0
-DA:404,0
-DA:405,0
-DA:406,0
-DA:409,0
-DA:410,0
-DA:414,0
-DA:415,0
-DA:418,0
-DA:419,0
-DA:424,0
-DA:425,0
-DA:426,0
-DA:427,0
-DA:428,0
-DA:429,0
-DA:439,0
-DA:446,0
-DA:447,0
-DA:448,0
-DA:449,0
-DA:450,0
-DA:451,0
-DA:454,0
-DA:455,0
-DA:456,0
-DA:457,0
-DA:458,0
-DA:459,0
-LF:195
-LH:2
+DA:218,0
+DA:220,0
+DA:221,0
+DA:222,0
+DA:224,0
+DA:225,0
+DA:226,0
+DA:228,0
+DA:230,0
+DA:231,0
+DA:232,0
+DA:233,0
+DA:237,0
+DA:238,0
+DA:240,0
+LF:113
+LH:0
end_of_record
-SF:lib\views\settings_view\settings_view_widgets\send_error_dialog.dart
-DA:10,16
-DA:12,0
-DA:13,0
-DA:17,0
+SF:lib\widgets\pulse_icon.dart
+DA:4,0
DA:19,0
DA:20,0
-DA:21,0
-DA:22,0
-DA:23,0
-DA:24,0
-DA:25,0
-DA:26,0
-DA:30,0
+DA:29,0
+DA:31,0
DA:32,0
DA:33,0
+DA:34,0
DA:35,0
-DA:37,0
DA:38,0
DA:39,0
-DA:40,0
DA:45,0
DA:47,0
DA:48,0
DA:51,0
+DA:52,0
+DA:53,0
DA:54,0
+DA:55,0
+DA:56,0
DA:57,0
+DA:58,0
DA:59,0
DA:60,0
DA:61,0
-DA:73,0
-DA:74,0
-DA:75,0
-DA:76,0
-DA:80,0
-DA:82,0
-DA:84,0
-DA:85,0
-DA:97,0
-DA:99,0
-DA:101,0
-DA:103,0
-DA:104,0
-DA:106,0
-DA:107,0
-DA:108,0
-DA:109,0
-DA:113,0
-LF:47
-LH:1
+DA:62,0
+DA:63,0
+DA:65,0
+DA:66,0
+DA:71,0
+LF:30
+LH:0
end_of_record
-SF:lib\widgets\default_dialog.dart
-DA:11,0
+SF:lib\widgets\tooltip_container.dart
+DA:9,0
+DA:18,0
DA:19,0
DA:20,0
DA:21,0
DA:22,0
DA:23,0
DA:24,0
-DA:30,0
-DA:31,0
+DA:25,0
+DA:26,0
+DA:27,0
+DA:28,0
+DA:34,0
+DA:35,0
+DA:36,0
+LF:15
+LH:0
+end_of_record
+SF:lib\widgets\home_widgets\interfaces\flutter_home_widget_base.dart
+DA:11,0
+LF:1
+LH:0
+end_of_record
+SF:lib\widgets\home_widgets\interfaces\flutter_home_widget_builder.dart
+DA:14,0
+DA:24,0
+DA:25,0
+DA:26,0
+DA:27,0
DA:32,0
-LF:10
+DA:33,0
+DA:34,0
+DA:35,0
+DA:36,0
+DA:38,0
+DA:39,0
+DA:40,0
+DA:41,0
+LF:14
LH:0
end_of_record
diff --git a/integration_test/add_tokens_test.dart b/integration_test/add_tokens_test.dart
index ff1ccd675..30e224114 100644
--- a/integration_test/add_tokens_test.dart
+++ b/integration_test/add_tokens_test.dart
@@ -14,7 +14,7 @@ import 'package:privacyidea_authenticator/state_notifiers/completed_introduction
import 'package:privacyidea_authenticator/state_notifiers/settings_notifier.dart';
import 'package:privacyidea_authenticator/state_notifiers/token_folder_notifier.dart';
import 'package:privacyidea_authenticator/state_notifiers/token_notifier.dart';
-import 'package:privacyidea_authenticator/utils/app_customizer.dart';
+import 'package:privacyidea_authenticator/utils/customization/application_customization.dart';
import 'package:privacyidea_authenticator/utils/riverpod_providers.dart';
import 'package:privacyidea_authenticator/views/add_token_manually_view/add_token_manually_view.dart';
import 'package:privacyidea_authenticator/views/add_token_manually_view/add_token_manually_view_widgets/labeled_dropdown_button.dart';
@@ -45,7 +45,7 @@ void main() {
when(mockTokenRepository.deleteTokens(any)).thenAnswer((_) async => []);
mockTokenFolderRepository = MockTokenFolderRepository();
when(mockTokenFolderRepository.loadFolders()).thenAnswer((_) async => []);
- when(mockTokenFolderRepository.saveOrReplaceFolders(any)).thenAnswer((_) async => []);
+ when(mockTokenFolderRepository.saveReplaceList(any)).thenAnswer((_) async => true);
mockIntroductionRepository = MockIntroductionRepository();
final introductions = {...Introduction.values}..remove(Introduction.introductionScreen);
when(mockIntroductionRepository.loadCompletedIntroductions()).thenAnswer((_) async => IntroductionState(completedIntroductions: introductions));
@@ -60,7 +60,7 @@ void main() {
tokenFolderProvider.overrideWith((ref) => TokenFolderNotifier(repository: mockTokenFolderRepository)),
introductionProvider.overrideWith((ref) => IntroductionNotifier(repository: mockIntroductionRepository)),
],
- child: PrivacyIDEAAuthenticator(customization: ApplicationCustomization.defaultCustomization),
+ child: PrivacyIDEAAuthenticator(ApplicationCustomization.defaultCustomization),
));
await _introToMainView(tester);
diff --git a/integration_test/copy_to_clipboard_test.dart b/integration_test/copy_to_clipboard_test.dart
index 3afe300b4..a020a2c29 100644
--- a/integration_test/copy_to_clipboard_test.dart
+++ b/integration_test/copy_to_clipboard_test.dart
@@ -12,9 +12,9 @@ import 'package:privacyidea_authenticator/model/tokens/hotp_token.dart';
import 'package:privacyidea_authenticator/state_notifiers/settings_notifier.dart';
import 'package:privacyidea_authenticator/state_notifiers/token_folder_notifier.dart';
import 'package:privacyidea_authenticator/state_notifiers/token_notifier.dart';
-import 'package:privacyidea_authenticator/utils/app_customizer.dart';
+import 'package:privacyidea_authenticator/utils/customization/application_customization.dart';
import 'package:privacyidea_authenticator/utils/riverpod_providers.dart';
-import 'package:privacyidea_authenticator/utils/version.dart';
+import 'package:privacyidea_authenticator/model/version.dart';
import '../test/tests_app_wrapper.dart';
import '../test/tests_app_wrapper.mocks.dart';
@@ -38,7 +38,7 @@ void main() {
when(mockTokenRepository.deleteTokens(any)).thenAnswer((_) async => []);
mockTokenFolderRepository = MockTokenFolderRepository();
when(mockTokenFolderRepository.loadFolders()).thenAnswer((_) async => []);
- when(mockTokenFolderRepository.saveOrReplaceFolders(any)).thenAnswer((_) async => []);
+ when(mockTokenFolderRepository.saveReplaceList(any)).thenAnswer((_) async => true);
mockIntroductionRepository = MockIntroductionRepository();
final introductions = {...Introduction.values}..remove(Introduction.introductionScreen);
when(mockIntroductionRepository.loadCompletedIntroductions()).thenAnswer((_) async => IntroductionState(completedIntroductions: introductions));
@@ -50,7 +50,7 @@ void main() {
tokenProvider.overrideWith((ref) => TokenNotifier(repository: mockTokenRepository)),
tokenFolderProvider.overrideWith((ref) => TokenFolderNotifier(repository: mockTokenFolderRepository)),
],
- child: PrivacyIDEAAuthenticator(customization: ApplicationCustomization.defaultCustomization),
+ child: PrivacyIDEAAuthenticator(ApplicationCustomization.defaultCustomization),
));
await tester.pumpAndSettle();
await pumpUntilFindNWidgets(tester, find.text('356 306'), 1, const Duration(seconds: 10));
diff --git a/integration_test/rename_and_delete_test.dart b/integration_test/rename_and_delete_test.dart
index b5c388b44..c33f191bb 100644
--- a/integration_test/rename_and_delete_test.dart
+++ b/integration_test/rename_and_delete_test.dart
@@ -13,9 +13,9 @@ import 'package:privacyidea_authenticator/state_notifiers/completed_introduction
import 'package:privacyidea_authenticator/state_notifiers/settings_notifier.dart';
import 'package:privacyidea_authenticator/state_notifiers/token_folder_notifier.dart';
import 'package:privacyidea_authenticator/state_notifiers/token_notifier.dart';
-import 'package:privacyidea_authenticator/utils/app_customizer.dart';
+import 'package:privacyidea_authenticator/utils/customization/application_customization.dart';
import 'package:privacyidea_authenticator/utils/riverpod_providers.dart';
-import 'package:privacyidea_authenticator/utils/version.dart';
+import 'package:privacyidea_authenticator/model/version.dart';
import 'package:privacyidea_authenticator/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_delete_action.dart';
import 'package:privacyidea_authenticator/views/main_view/main_view_widgets/token_widgets/hotp_token_widgets/actions/edit_hotp_token_action.dart';
import 'package:privacyidea_authenticator/views/main_view/main_view_widgets/token_widgets/hotp_token_widgets/hotp_token_widget.dart';
@@ -42,7 +42,7 @@ void main() {
when(mockTokenRepository.deleteTokens(any)).thenAnswer((_) async => []);
mockTokenFolderRepository = MockTokenFolderRepository();
when(mockTokenFolderRepository.loadFolders()).thenAnswer((_) async => []);
- when(mockTokenFolderRepository.saveOrReplaceFolders(any)).thenAnswer((_) async => []);
+ when(mockTokenFolderRepository.saveReplaceList(any)).thenAnswer((_) async => true);
mockIntroductionRepository = MockIntroductionRepository();
final introductions = {...Introduction.values}..remove(Introduction.introductionScreen);
when(mockIntroductionRepository.loadCompletedIntroductions()).thenAnswer((_) async => IntroductionState(completedIntroductions: introductions));
@@ -55,7 +55,7 @@ void main() {
tokenFolderProvider.overrideWith((ref) => TokenFolderNotifier(repository: mockTokenFolderRepository)),
introductionProvider.overrideWith((ref) => IntroductionNotifier(repository: mockIntroductionRepository)),
],
- child: PrivacyIDEAAuthenticator(customization: ApplicationCustomization.defaultCustomization),
+ child: PrivacyIDEAAuthenticator(ApplicationCustomization.defaultCustomization),
));
await _renameToken(tester, 'Renamed Token');
await _renameToken(tester, 'Renamed Token Again');
diff --git a/integration_test/two_step_rollout_test.dart b/integration_test/two_step_rollout_test.dart
index dc61107e3..bb1a400b4 100644
--- a/integration_test/two_step_rollout_test.dart
+++ b/integration_test/two_step_rollout_test.dart
@@ -10,10 +10,10 @@ import 'package:privacyidea_authenticator/model/states/settings_state.dart';
import 'package:privacyidea_authenticator/state_notifiers/settings_notifier.dart';
import 'package:privacyidea_authenticator/state_notifiers/token_folder_notifier.dart';
import 'package:privacyidea_authenticator/state_notifiers/token_notifier.dart';
-import 'package:privacyidea_authenticator/utils/app_customizer.dart';
+import 'package:privacyidea_authenticator/utils/customization/application_customization.dart';
import 'package:privacyidea_authenticator/utils/logger.dart';
import 'package:privacyidea_authenticator/utils/riverpod_providers.dart';
-import 'package:privacyidea_authenticator/utils/version.dart';
+import 'package:privacyidea_authenticator/model/version.dart';
import 'package:privacyidea_authenticator/views/main_view/main_view.dart';
import 'package:privacyidea_authenticator/views/main_view/main_view_widgets/token_widgets/hotp_token_widgets/hotp_token_widget_tile.dart';
import 'package:privacyidea_authenticator/views/main_view/main_view_widgets/token_widgets/totp_token_widgets/totp_token_widget_tile.dart';
@@ -22,26 +22,6 @@ import 'package:privacyidea_authenticator/widgets/widget_keys.dart';
import '../test/tests_app_wrapper.dart';
import '../test/tests_app_wrapper.mocks.dart';
-/*
-
-// qr codes:
-const String URI_TYPE = 'URI_TYPE';
-const String URI_LABEL = 'URI_LABEL';
-const String URI_ALGORITHM = 'URI_ALGORITHM';
-const String URI_DIGITS = 'URI_DIGITS';
-const String URI_SECRET = 'URI_SECRET';
-const String URI_COUNTER = 'URI_COUNTER';
-const String URI_PERIOD = 'URI_PERIOD';
-const String URI_ISSUER = 'URI_ISSUER';
-const String URI_PIN = 'URI_PIN';
-const String URI_IMAGE = 'URI_IMAGE';
-
-// 2 step:
-const String URI_SALT_LENGTH = 'URI_SALT_LENGTH';
-const String URI_OUTPUT_LENGTH_IN_BYTES = 'URI_OUTPUT_LENGTH_IN_BYTES';
-const String URI_ITERATIONS = 'URI_ITERATIONS';
-
- */
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
late final MockSettingsRepository mockSettingsRepository;
@@ -59,7 +39,7 @@ void main() {
when(mockTokenRepository.deleteTokens(any)).thenAnswer((_) async => []);
mockTokenFolderRepository = MockTokenFolderRepository();
when(mockTokenFolderRepository.loadFolders()).thenAnswer((_) async => []);
- when(mockTokenFolderRepository.saveOrReplaceFolders(any)).thenAnswer((_) async => []);
+ when(mockTokenFolderRepository.saveReplaceList(any)).thenAnswer((_) async => true);
mockIntroductionRepository = MockIntroductionRepository();
final introductions = {...Introduction.values}..remove(Introduction.introductionScreen);
when(mockIntroductionRepository.loadCompletedIntroductions()).thenAnswer((_) async => IntroductionState(completedIntroductions: introductions));
@@ -73,7 +53,7 @@ void main() {
tokenProvider.overrideWith((ref) => TokenNotifier(repository: mockTokenRepository)),
tokenFolderProvider.overrideWith((ref) => TokenFolderNotifier(repository: mockTokenFolderRepository)),
],
- child: PrivacyIDEAAuthenticator(customization: ApplicationCustomization.defaultCustomization),
+ child: PrivacyIDEAAuthenticator(ApplicationCustomization.defaultCustomization),
));
await _addTwoStepHotpTokenTest(tester);
await _addTwoStepTotpTokenTest(tester);
diff --git a/integration_test/views_test.dart b/integration_test/views_test.dart
index 7e189b26f..35015e40b 100644
--- a/integration_test/views_test.dart
+++ b/integration_test/views_test.dart
@@ -12,10 +12,10 @@ import 'package:privacyidea_authenticator/model/states/settings_state.dart';
import 'package:privacyidea_authenticator/state_notifiers/settings_notifier.dart';
import 'package:privacyidea_authenticator/state_notifiers/token_folder_notifier.dart';
import 'package:privacyidea_authenticator/state_notifiers/token_notifier.dart';
-import 'package:privacyidea_authenticator/utils/app_customizer.dart';
+import 'package:privacyidea_authenticator/utils/customization/application_customization.dart';
import 'package:privacyidea_authenticator/utils/riverpod_providers.dart';
import 'package:privacyidea_authenticator/utils/rsa_utils.dart';
-import 'package:privacyidea_authenticator/utils/version.dart';
+import 'package:privacyidea_authenticator/model/version.dart';
import 'package:privacyidea_authenticator/views/settings_view/settings_view_widgets/settings_groups.dart';
import '../test/tests_app_wrapper.dart';
@@ -41,7 +41,7 @@ void main() {
when(mockTokenRepository.deleteTokens(any)).thenAnswer((_) async => []);
mockTokenFolderRepository = MockTokenFolderRepository();
when(mockTokenFolderRepository.loadFolders()).thenAnswer((_) async => []);
- when(mockTokenFolderRepository.saveOrReplaceFolders(any)).thenAnswer((_) async => []);
+ when(mockTokenFolderRepository.saveReplaceList(any)).thenAnswer((_) async => true);
mockRsaUtils = MockRsaUtils();
when(mockRsaUtils.serializeRSAPublicKeyPKCS8(any)).thenAnswer((_) => 'publicKey');
when(mockRsaUtils.generateRSAKeyPair()).thenAnswer((_) => const RsaUtils()
@@ -72,7 +72,7 @@ void main() {
)),
tokenFolderProvider.overrideWith((ref) => TokenFolderNotifier(repository: mockTokenFolderRepository)),
],
- child: PrivacyIDEAAuthenticator(customization: ApplicationCustomization.defaultCustomization),
+ child: PrivacyIDEAAuthenticator(ApplicationCustomization.defaultCustomization),
));
await _licensesViewTest(tester);
diff --git a/ios/Flutter/Flutter.podspec b/ios/Flutter/Flutter.podspec
deleted file mode 100644
index 98e163395..000000000
--- a/ios/Flutter/Flutter.podspec
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# This podspec is NOT to be published. It is only used as a local source!
-# This is a generated file; do not edit or check into version control.
-#
-
-Pod::Spec.new do |s|
- s.name = 'Flutter'
- s.version = '1.0.0'
- s.summary = 'A UI toolkit for beautiful and fast apps.'
- s.homepage = 'https://flutter.dev'
- s.license = { :type => 'BSD' }
- s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
- s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
- s.ios.deployment_target = '12.0'
- # Framework linking is handled by Flutter tooling, not CocoaPods.
- # Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs.
- s.vendored_frameworks = 'path/to/nothing'
-end
diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh
index 0d9da0fd3..f8c05ec23 100755
--- a/ios/Flutter/flutter_export_environment.sh
+++ b/ios/Flutter/flutter_export_environment.sh
@@ -5,9 +5,8 @@ export "FLUTTER_APPLICATION_PATH=/Users/frankmerkel/Documents/GitHub/pi-authenti
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_TARGET=/Users/frankmerkel/Documents/GitHub/pi-authenticator/lib/mains/main_netknights.dart"
export "FLUTTER_BUILD_DIR=build"
-export "FLUTTER_BUILD_NAME=4.3.1"
-export "FLUTTER_BUILD_NUMBER=403106"
-export "DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==,RkxVVFRFUl9XRUJfQ0FOVkFTS0lUX1VSTD1odHRwczovL3d3dy5nc3RhdGljLmNvbS9mbHV0dGVyLWNhbnZhc2tpdC8yZTRiYTljNmZiNDk5Y2NkNGU4MTQyMDU0Mzc4M2NjNzI2N2FlNDA2Lw==,RkxVVFRFUl9BUFBfRkxBVk9SPW5ldGtuaWdodHM="
+export "FLUTTER_BUILD_NAME=4.4.0"
+export "FLUTTER_BUILD_NUMBER=404001"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index cf370fc4d..6b4d03e97 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -10,6 +10,7 @@
0DCCE7B526CE7AA30029E1D5 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+ 5155DCDE5F4DD400F5DF6ECC /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F4640C1CB92CE5806393BD0 /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
@@ -41,6 +42,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 02E06BAE53E4F69214BE5161 /* Pods-Runner.release-netknights.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-netknights.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-netknights.xcconfig"; sourceTree = ""; };
0D32FBC526A84C0B0033DD09 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Main.strings; sourceTree = ""; };
0D32FBC626A84C0B0033DD09 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/LaunchScreen.strings; sourceTree = ""; };
0D32FBC726A84E6D0033DD09 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Main.strings; sourceTree = ""; };
@@ -62,7 +64,7 @@
92455F34F4CD3178F657D07D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
- 97C146EE1CF9000F007C117D /* privacyIDEA Authenticator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "privacyIDEA Authenticator.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 97C146EE1CF9000F007C117D /* (debug) privacyIDEA Authenticator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "(debug) privacyIDEA Authenticator.app"; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
@@ -154,7 +156,7 @@
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
- 97C146EE1CF9000F007C117D /* privacyIDEA Authenticator.app */,
+ 97C146EE1CF9000F007C117D /* (debug) privacyIDEA Authenticator.app */,
);
name = Products;
sourceTree = "";
@@ -207,7 +209,7 @@
);
name = Runner;
productName = Runner;
- productReference = 97C146EE1CF9000F007C117D /* privacyIDEA Authenticator.app */;
+ productReference = 97C146EE1CF9000F007C117D /* (debug) privacyIDEA Authenticator.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
@@ -254,7 +256,7 @@
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
- 0DCCE7B526CE7AA30029E1D5 /* BuildFile in Resources */,
+ 0DCCE7B526CE7AA30029E1D5 /* (null) in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
@@ -263,6 +265,98 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
+ 19B242C1346AC637BC733F43 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework",
+ "${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework",
+ "${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework",
+ "${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework",
+ "${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework",
+ "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
+ "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework",
+ "${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework",
+ "${BUILT_PRODUCTS_DIR}/SwiftyRSA/SwiftyRSA.framework",
+ "${BUILT_PRODUCTS_DIR}/app_minimizer/app_minimizer.framework",
+ "${BUILT_PRODUCTS_DIR}/camera_avfoundation/camera_avfoundation.framework",
+ "${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework",
+ "${BUILT_PRODUCTS_DIR}/device_info_plus/device_info_plus.framework",
+ "${BUILT_PRODUCTS_DIR}/file_selector_ios/file_selector_ios.framework",
+ "${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework",
+ "${BUILT_PRODUCTS_DIR}/flutter_mailer/flutter_mailer.framework",
+ "${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework",
+ "${BUILT_PRODUCTS_DIR}/home_widget/home_widget.framework",
+ "${BUILT_PRODUCTS_DIR}/integration_test/integration_test.framework",
+ "${BUILT_PRODUCTS_DIR}/local_auth_darwin/local_auth_darwin.framework",
+ "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
+ "${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework",
+ "${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework",
+ "${BUILT_PRODUCTS_DIR}/pi_authenticator_legacy/pi_authenticator_legacy.framework",
+ "${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework",
+ "${BUILT_PRODUCTS_DIR}/uni_links/uni_links.framework",
+ "${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreInternal.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyRSA.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/app_minimizer.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/camera_avfoundation.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info_plus.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_selector_ios.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_mailer.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/home_widget.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/integration_test.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/local_auth_darwin.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/pi_authenticator_legacy.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/uni_links.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 2AD8F18CAC5ADF0FEB8B4915 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
36AD5FCC2B83563A00FB5A82 /* Copy GoogleService-Info.plist */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -533,7 +627,7 @@
);
MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
PRODUCT_BUNDLE_IDENTIFIER = privacyidea.authenticator;
- PRODUCT_NAME = "privacyIDEA Authenticator";
+ PRODUCT_NAME = "(debug) privacyIDEA Authenticator";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 8a1ae9722..48db00e09 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -84,5 +84,11 @@
UIViewControllerBasedStatusBarAppearance
+ UISupportsDocumentBrowser
+
+ LSSupportsOpeningDocumentsInPlace
+
+ UIFileSharingEnabled
+
diff --git a/lib/extensions/color_extension.dart b/lib/extensions/color_extension.dart
deleted file mode 100644
index a8a207cb3..000000000
--- a/lib/extensions/color_extension.dart
+++ /dev/null
@@ -1,21 +0,0 @@
-import 'dart:ui';
-
-extension ColorExtension on Color {
- Color mixWith(Color other) {
- return Color.fromARGB(
- (alpha + other.alpha) ~/ 2.clamp(0, 255),
- (red + other.red) ~/ 2.clamp(0, 255),
- (green + other.green) ~/ 2.clamp(0, 255),
- (blue + other.blue) ~/ 2.clamp(0, 255),
- );
- }
-
- Color opposite() {
- return Color.fromARGB(
- alpha,
- 255 - red,
- 255 - green,
- 255 - blue,
- );
- }
-}
diff --git a/lib/extensions/theme_mode_extension.dart b/lib/extensions/theme_mode_extension.dart
deleted file mode 100644
index 664912904..000000000
--- a/lib/extensions/theme_mode_extension.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-import 'package:flutter/material.dart';
-
-extension ThemeModeExtension on ThemeMode {
- String get name {
- switch (this) {
- case ThemeMode.system:
- return 'System';
- case ThemeMode.light:
- return 'Light';
- case ThemeMode.dark:
- return 'Dark';
- default:
- return 'Unknown';
- }
- }
-}
diff --git a/lib/interfaces/repo/push_request_repository.dart b/lib/interfaces/repo/push_request_repository.dart
index 040bf906d..09b126888 100644
--- a/lib/interfaces/repo/push_request_repository.dart
+++ b/lib/interfaces/repo/push_request_repository.dart
@@ -1,7 +1,11 @@
-import '../../model/push_request.dart';
+import '../../model/push_request.dart' show PushRequest;
+import '../../model/states/push_request_state.dart' show PushRequestState;
abstract class PushRequestRepository {
- Future saveOrReplacePushRequests(List pushRequests);
- Future> loadPushRequests();
- Future deletePushRequest(PushRequest pushRequest);
+ Future loadState();
+ Future saveState(PushRequestState pushRequestState);
+ Future clearState();
+
+ Future add(PushRequest pushRequest, {PushRequestState? state});
+ Future remove(PushRequest pushRequest, {PushRequestState? state});
}
diff --git a/lib/interfaces/repo/token_folder_repository.dart b/lib/interfaces/repo/token_folder_repository.dart
index 9a6f4055c..053acc9f6 100644
--- a/lib/interfaces/repo/token_folder_repository.dart
+++ b/lib/interfaces/repo/token_folder_repository.dart
@@ -1,6 +1,8 @@
import '../../model/token_folder.dart';
abstract class TokenFolderRepository {
- Future> saveOrReplaceFolders(List folders);
+ /// Overwrite the current state with the new folders
+ /// Returns true if the operation is successful, false otherwise
+ Future saveReplaceList(List folders);
Future> loadFolders();
}
diff --git a/lib/interfaces/repo/token_repository.dart b/lib/interfaces/repo/token_repository.dart
index c15d34211..cda5e9752 100644
--- a/lib/interfaces/repo/token_repository.dart
+++ b/lib/interfaces/repo/token_repository.dart
@@ -1,9 +1,21 @@
import '../../model/tokens/token.dart';
abstract class TokenRepository {
- Future> saveOrReplaceTokens(List tokens);
+ /// Returns the saved Token with the given id.
+ Future loadToken(String id);
+
+ /// Returns all saved Tokens.
Future> loadTokens();
- //Returns the tokens that were not deleted
- Future> deleteTokens(List tokens);
+ /// Returns true if the Token was saved successfully.
+ Future saveOrReplaceToken(Token token);
+
+ /// Returns the tokens that were not saved successfully.
+ Future> saveOrReplaceTokens(List tokens);
+
+ /// Returns true if the Token was deleted successfully.
+ Future deleteToken(Token token);
+
+ /// Returns the tokens that were not deleted successfully.
+ Future> deleteTokens(List tokens);
}
diff --git a/lib/l10n/app_cs.arb b/lib/l10n/app_cs.arb
index 111a234dd..5a6caa7d6 100644
--- a/lib/l10n/app_cs.arb
+++ b/lib/l10n/app_cs.arb
@@ -163,6 +163,12 @@
"@systemTheme": {
"description": "The systems theme."
},
+ "someTokensDoNotSupportPolling": "Některé tokeny jsou zastaralé a nepodporují polling",
+ "@someTokensDoNotSupportPolling": {
+ "description": "Tells the user, that the following tokens do not support polling.",
+ "type": "text",
+ "placeholders": {}
+ },
"enablePolling": "Povolit polling",
"@enablePolling": {
"description": "Name of the setting switch that enables polling."
@@ -536,6 +542,7 @@
"invalidQrScan": "Naskenovaný QR kód není platnou zálohou {appName}.",
"invalidQrFile": "Vybraný soubor neobsahuje platný QR kód z {appName}.",
"invalidLink": "Zadaný odkaz není platným tokenem {appName} nebo není podporován.",
+ "importFailedToken": "{count, plural, zero{Žádný token Nepodařilo se importovat.} one{Nepodařilo se importovat token.} other{Nepodařilo se importovat {count} tokenů.}}",
"importExistingToken": "{count, plural, zero{Nebyl nalezen žádný token, který by se již v aplikaci nacházel.} one{Byl nalezen token, který již v aplikaci existuje.} other{{count} byly nalezeny tokeny, které se již v aplikaci nacházejí.}}",
"importConflictToken": "{count, plural, zero{Není žádný konflikt s tokeny, které již existují.} one{Je konflikt s tokeny, které již existují.\nProsím, vyberte, který z nich chcete zachovat.} other{Je konflikt s tokeny, které již existují.\nProsím, vyberte, který z nich chcete zachovat.}}",
"importNewToken": "{count, plural, zero{Nenalezen žádný nový token.} one{Nalezen nový token, který bude importován.} other{Nalezen nový token {count}, který bude importován.}}",
@@ -545,6 +552,9 @@
"importHintAegisLink": "Zadejte odkaz, který obdržíte při přenosu záznamů ze systému Aegis.",
"importHintGoogleQrScan": "Naskenujte QR kód, který obdržíte při exportu účtů z Google Authenticator.",
"importHintGoogleQrFile": "Vyberte obrazový soubor s QR kódem, který obdržíte při exportu účtů z Google Authenticator.\n!! Upozorňujeme, že není bezpečné ukládat QR kód do zařízení, protože tokeny nejsou šifrovány !!",
+ "importHintAuthenticatorProFile": "Chcete-li vytvořit zálohu aplikace Authenticator Pro, přejděte do nastavení a klepněte na položku \"Automatické zálohování\". Vyberte umístění úložiště a nastavte heslo. Poté stiskněte \"Zálohovat nyní\" a exportujte tokeny.",
+ "importHintFreeOtpPlusQrScan": "Naskenujte QR kód, který obdržíte po stisknutí tří teček na dlaždici tokenu, a vyberte možnost \"Sdílet QR kód\".",
+ "importHintFreeOtpPlusFile": "Chcete-li vytvořit zálohu aplikace FreeOTP+, klepněte na tři tečky v pravém horním rohu a vyberte možnost \"Exportovat\". Můžete si vybrat mezi formátem JSON a URI. Zálohu doporučujeme po importu odstranit, protože není šifrovaná.",
"qrFileDecodeError": "Z vybraného obrázku nebylo možné dekódovat QR kód, použijte prosím místo toho skener QR kódů.",
"tokenLink": "Token link",
"feedback": "Zpětná vazba",
@@ -575,5 +585,55 @@
"example": "GitHub"
}
}
- }
+ },
+ "errorUnlinkingPushToken": "Nepodařilo se odlinkovat push token {label}.",
+ "@errorUnlinkingPushToken": {
+ "description": "Error message when unlinking a push token failed.",
+ "placeholders": {
+ "label": {
+ "example": "PUSH1234A"
+ }
+ }
+ },
+ "pleaseSyncManuallyWhenNetworkIsAvailable": "Synchronizujte prosím push tokeny ručně prostřednictvím nastavení, když je k dispozici síťové připojení.",
+ "pushTokens": "Žetony Push",
+ "continueButton": "Pokračovat",
+ "addTokenManually": "Přidat token ručně",
+ "addFolder": "Přidat složku",
+ "searchTokens": "Hledat tokeny",
+ "closeSearchTokens": "Zavřít vyhledávání",
+ "increaseCounter": "Zvýšit počítadla",
+ "copyOTPToClipboard": "Zkopírovat OTP do schránky",
+ "licenses": "Licence",
+ "optionalMessage": "Volitelná zpráva",
+ "confirmation": "Potvrzení",
+ "askLogSendedDescription": "Odeslali jste protokol a chcete jej nyní vymazat?",
+ "algorithmUnsupported": "Algoritmus {algorithm} není podporován",
+ "@algorithmUnsupported": {
+ "placeholders": {
+ "algorithm": {
+ "example": "MD5"
+ }
+ }
+ },
+ "thisAppIsOpenSource": "Tato aplikace má otevřený zdrojový kód\nNavštivte nás na GitHub",
+ "invalidArgument": "{argument} není platná hodnota pro {type}",
+ "importExportTokens": "Import/Exportovat žetony",
+ "exportNonPrivacyIDEATokens": "Exportovat ne-privacyIDEA žetony",
+ "selectTokensToExport": "{count, plural, zero{} one{Vyberte žeton k exportu} other{Vyberte žetony k exportu}}",
+ "noTokensToExport": "Žádné žetony k exportu",
+ "exportAllTokens": "Exportovat všechny žetony",
+ "export": "Export",
+ "exportingTokens": "Probíhá export žetonů...",
+ "exportTokens": "Exportovat žetony",
+ "enterPasswordToEncrypt": "Zadejte heslo pro šifrování žetonů. Toto heslo bude vyžadováno k importu žetonů.",
+ "exportLockedTokenReason": "Prosím, ověřte se, abyste mohli exportovat uzamčené žetony.",
+ "fileSavedToDownloadsFolder": "Soubor uložen do složky Stažené soubory",
+ "errorSavingFile": "Chyba při ukládání souboru",
+ "toFile": "Do souboru",
+ "asQrCode": "Jako QR kód",
+ "scanThisQrWithNewDevice": "Naskenujte tento QR kód svým novým zařízením pro import žetonu.",
+ "oneMore": "Ještě jeden",
+ "done": "Hotovo",
+ "confirmPassword": "Potvrďte heslo"
}
\ No newline at end of file
diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb
index 04a386aa5..9b32055d6 100644
--- a/lib/l10n/app_de.arb
+++ b/lib/l10n/app_de.arb
@@ -7,7 +7,7 @@
"patchNotesV4_3_1Improvement1": "Der QR-Code-Scanner wurde verbessert.",
"patchNotesV4_3_0NewFeatures1": "Unterstützung für den Import von Token von Google, Aegis und 2FAS Authenticator hinzugefügt. Weitere Importquellen werden in Zukunft hinzugefügt.",
"patchNotesV4_3_0NewFeatures2": "Feedback-Option zu den Einstellungen hinzugefügt.",
- "patchNotesV4_3_0NewFeatures3": "Push-Tokens können jetzt aus der Token-Liste ausgeblendet werden.",
+ "patchNotesV4_3_0NewFeatures3": "Push-Token können jetzt aus der Token-Liste ausgeblendet werden.",
"patchNotesV4_3_0NewFeatures4": "Es wurden Einführungen hinzugefügt, um neuen Benutzern den Einstieg zu erleichtern.",
"patchNotesV4_3_0NewFeatures5": "Sie können jetzt nach Token suchen, indem Sie auf die Lupe in der oberen rechten Ecke tippen.",
"patchNotesV4_3_0NewFeatures6": "Ab Android 12 kann für einen Token ein Widget auf dem Homescreen erstellt werden.",
@@ -161,6 +161,12 @@
"@systemTheme": {
"description": "The systems theme."
},
+ "someTokensDoNotSupportPolling": "Einige der Token sind veraltet und unterstützen keine aktiven Anfragen",
+ "@someTokensDoNotSupportPolling": {
+ "description": "Tells the user, that the following tokens do not support polling.",
+ "type": "text",
+ "placeholders": {}
+ },
"enablePolling": "Aktives Stellen von Push-Anfragen",
"@enablePolling": {
"description": "Name of the setting switch that enables polling."
@@ -515,8 +521,9 @@
"invalidQrScan": "Der gescannte QR-Code ist kein gültiges Backup von {appName}.",
"invalidQrFile": "Die ausgewählte Datei enthällt kein gültigen QR-Code von {appName}.",
"invalidLink": "Der eingegebene Link ist kein gültiger Token von {appName}, oder er wird nicht unterstützt.",
+ "importFailedToken": "{count, plural, zero{Kein Token konnte nicht importiert werden.} one{Importieren eines Tokens fehlgeschlagen.} other{Der Import von {count} Token ist fehlgeschlagen.}}",
"importExistingToken": "{count, plural, zero{Es wurde kein Token gefunden, das sich bereits in der App befindet.} one{Es wurde ein Token gefunden, das sich bereits in der Anwendung befindet.} other{Es wurden {count} Token gefunden, die sich bereits in der Anwendung befinden.}}",
- "importConflictToken": "{count, plural, zero{Es besteht kein Konflikt mit bereits existierenden Token.} one{Es besteht ein Konflikt mit bereits existierenden Token.\nBitte wählen Sie aus, welches Sie behalten möchten.} other{Es besteht ein Konflikt mit bereits existierenden Token.\nBitte wählen Sie aus, welches Sie behalten möchten.}}",
+ "importConflictToken": "{count, plural, zero{Es besteht kein Konflikt mit bereits existierenden Token.} one{Es besteht ein Konflikt mit bereits vorhandenen Token.\nBitte wählen Sie aus, welches Sie behalten möchten.} other{Es bestehen Konflikte mit bereits vorhandenen Token.\nBitte wählen Sie die Token aus, die Sie behalten möchten.}}",
"importNewToken": "{count, plural, zero{Es wurde kein neues Token gefunden.} one{Es wurde ein neues Token gefunden, das importiert wird.} other{Es wurden {count} neue Token gefunden, die importiert werden.}}",
"importHint2FAS": "Wählen Sie das 2FAS-Backup aus.\nFalls Sie kein Backup haben, erstellen Sie eins in der 2FAS-App. Wir empfehlen die Verwendung eines Passworts.",
"importHintAegisBackupFile": "Wähle dein Aegis-Export (.json) aus.\nWenn Sie keinen Export haben, erstellen Sie bitte eins über das Einstellungen Menu in der Aegis-App. Wir empfehlen die Verwendung eines Passworts.",
@@ -524,6 +531,9 @@
"importHintAegisLink": "Geben Sie den Link ein, den Sie erhalten, wenn Sie Einträge aus Aegis übertragen.",
"importHintGoogleQrScan": "Scannen Sie den QR-Code, den Sie erhalten, wenn Sie Ihre Konten aus Google Authenticator exportieren.",
"importHintGoogleQrFile": "Wählen Sie eine Bilddatei mit dem QR-Code, den Sie erhalten, wenn Sie Ihre Konten aus dem Google Authenticator exportieren.\n!! Der QR-Code enthält die Token in unverschlüsselter Form. Es ist deshalb nicht sicher, diesen länger als nötig aufzubewahren !!",
+ "importHintAuthenticatorProFile": "Um ein Backup der Authenticator Pro-App zu erstellen navigieren Sie zu den Einstellungen und tippen Sie auf \"Automatische Sicherung\". Wählen Sie einen Speicherort und setzen Sie ein Passwort. Anschließend drücken Sie auf \"Jetzt sichern\" um die Token zu exportieren.",
+ "importHintFreeOtpPlusQrScan": "Scannen Sie den QR-Code, den Sie erhalten, wenn Sie auf die drei Punkte in der Kachel des Tokens drücken, und wählen Sie \"QR-Code teilen\".",
+ "importHintFreeOtpPlusFile": "Um ein Backup der FreeOTP+ App zu erstellen, tippen Sie auf die drei Punkte in der oberen rechten Ecke und wählen Sie \"Exportieren\". Sie können zwischen dem JSON- und dem URI-Format wählen. Wir empfehlen, das Backup nach dem Importieren zu löschen, da es nicht verschlüsselt ist.",
"qrFileDecodeError": "Es war nicht möglich, den QR-Code aus dem ausgewählten Bild zu dekodieren. Bitte verwenden Sie stattdessen den QR-Code-Scanner.",
"tokenLink": "Token Link",
"feedback": "Feedback",
@@ -554,5 +564,55 @@
"example": "GitHub"
}
}
- }
+ },
+ "errorUnlinkingPushToken": "Entkoppeln des Push Tokens {label} fehlgeschlagen.",
+ "@errorUnlinkingPushToken": {
+ "description": "Error message when unlinking a push token failed.",
+ "placeholders": {
+ "label": {
+ "example": "PUSH1234A"
+ }
+ }
+ },
+ "pleaseSyncManuallyWhenNetworkIsAvailable": "Bitte synchronisieren Sie die Push Token über die Einstellungen manuell, wenn eine Netzwerkverbindung verfügbar ist.",
+ "pushTokens": "Push-Token",
+ "continueButton": "Weiter",
+ "addTokenManually": "Token manuell hinzufügen",
+ "addFolder": "Ordner hinzufügen",
+ "searchTokens": "Token suchen",
+ "closeSearchTokens": "Suche schließen",
+ "increaseCounter": "Zähler erhöhen",
+ "copyOTPToClipboard": "OTP in die Zwischenablage kopieren",
+ "licenses": "Lizenzen",
+ "optionalMessage": "Optionale Nachricht",
+ "confirmation": "Confirmation",
+ "askLogSendedDescription": "Haben Sie das Protokoll gesendet, und möchten Sie es jetzt löschen?",
+ "algorithmUnsupported": "Der Algorithmus {algorithm} wird nicht unterstützt",
+ "@algorithmUnsupported": {
+ "placeholders": {
+ "algorithm": {
+ "example": "MD5"
+ }
+ }
+ },
+ "thisAppIsOpenSource": "Diese App ist Open Source\nBesuchen Sie uns auf GitHub",
+ "invalidArgument": "{argument} ist kein gültiger Wert für {type}",
+ "importExportTokens": "Token importieren/exportieren",
+ "exportNonPrivacyIDEATokens": "Nicht-privacyIDEA-Token exportieren",
+ "selectTokensToExport": "{count, plural, zero{} one{Wählen Sie das zu exportierende Token aus} other{Wählen Sie die zu exportierenden Tokens aus}}",
+ "noTokensToExport": "Keine Tokens zum Exportieren",
+ "exportAllTokens": "Alle Tokens exportieren",
+ "export": "Exportieren",
+ "exportingTokens": "Tokens werden exportiert...",
+ "exportTokens": "Tokens exportieren",
+ "enterPasswordToEncrypt": "Geben Sie ein Passwort ein, um die Tokens zu verschlüsseln. Dieses Passwort wird benötigt, um die Tokens zu importieren.",
+ "exportLockedTokenReason": "Bitte authentifizieren Sie sich, um gesperrte Tokens zu exportieren.",
+ "fileSavedToDownloadsFolder": "Datei wurde im Download-Ordner gespeichert",
+ "errorSavingFile": "Fehler beim Speichern der Datei",
+ "toFile": "In Datei",
+ "asQrCode": "Als QR-Code",
+ "scanThisQrWithNewDevice": "Scannen Sie diesen QR-Code mit Ihrem neuen Gerät, um das Token zu importieren.",
+ "oneMore": "Noch eins",
+ "done": "Fertig",
+ "confirmPassword": "Passwort bestätigen"
}
\ No newline at end of file
diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb
index c9e0d0cb7..2937cd9e0 100644
--- a/lib/l10n/app_en.arb
+++ b/lib/l10n/app_en.arb
@@ -153,6 +153,12 @@
"@systemTheme": {
"description": "The systems theme."
},
+ "someTokensDoNotSupportPolling": "Some of the tokens are outdated and do not support polling",
+ "@someTokensDoNotSupportPolling": {
+ "description": "Tells the user, that the following tokens do not support polling.",
+ "type": "text",
+ "placeholders": {}
+ },
"enablePolling": "Enable polling",
"@enablePolling": {
"description": "Name of the setting switch that enables polling."
@@ -526,8 +532,9 @@
"invalidQrScan": "The scanned QR code is not a valid backup of {appName}.",
"invalidQrFile": "The selected file does not contain a valid QR code from {appName}.",
"invalidLink": "The link entered is not a valid token of {appName}, or it is not supported.",
+ "importFailedToken": "{count, plural, zero{No token Failed to import.} one{Failed to import a token.} other{Failed to import {count} tokens.}}",
"importExistingToken": "{count, plural, zero{No token was found that is already in the application.} one{A token was found that already exists in the application.} other{{count} tokens was found that are already in the application.}}",
- "importConflictToken": "{count, plural, zero{There is no conflict with existing tokens.} one{There is a conflict with an existing token.\nPlease choose which one you want to keep.} other{There are conflicts with existing tokens.\nPlease choose which one you want to keep.}}",
+ "importConflictToken": "{count, plural, zero{There is no conflict with existing tokens.} one{There is a conflict with existing tokens.\nPlease select which one you would like to keep.} other{There are conflicts with existing tokens.\nPlease select the tokens you wish to keep.}}",
"importNewToken": "{count, plural, zero{No new token has been found.} one{A new token has been found and is being imported.} other{{count} new tokens have been found and will be imported.}}",
"importHint2FAS": "Select your 2FAS backup.\nIf you do not have a backup, create one in the 2FAS app. We recommend using a password.",
"importHintAegisBackupFile": "Select your Aegis export (.JSON).\nIf you do not have an export, please create one via the settings menu in the Aegis app. The use of a password is recommended.",
@@ -535,6 +542,9 @@
"importHintAegisLink": "Enter the link you receive when you transfer entries from Aegis.",
"importHintGoogleQrScan": "Scan the QR code you receive when you export your accounts from Google Authenticator.",
"importHintGoogleQrFile": "Select an image file with the QR code you receive when you export your accounts from Google Authenticator.\n!! Note that it is not safe to save the QR code on your device as the tokens are not encrypted !!",
+ "importHintAuthenticatorProFile": "To create a backup of the Authenticator Pro app, navigate to the settings and tap on \"Auto backup\". Select a storage location and set a password. Then press \"Back up now\" to export the tokens.",
+ "importHintFreeOtpPlusQrScan": "Scan the QR code you receive when you press the three dots in the tile of the token and select \"Share QR code\".",
+ "importHintFreeOtpPlusFile": "To create a backup of the FreeOTP+ app, tap on the three dots in the upper right corner and select \"Export\". You can choose between JSON and URI format. We recommend to delete the backup after importing it, because it is not encrypted.",
"qrFileDecodeError": "It was not possible to decode the QR code from the selected image, please use the QR code scanner instead.",
"tokenLink": "Token link",
"feedback": "Feedback",
@@ -566,5 +576,86 @@
"example": "GitHub"
}
}
+ },
+ "errorUnlinkingPushToken": "Failed to unlink the push token {label}.",
+ "@errorUnlinkingPushToken": {
+ "description": "Error message when unlinking a push token failed.",
+ "placeholders": {
+ "label": {
+ "example": "PUSH1234A"
+ }
+ }
+ },
+ "pleaseSyncManuallyWhenNetworkIsAvailable": "Please synchronize the push tokens manually via the settings when a network connection is available.",
+ "pushTokens": "Push Tokens",
+ "continueButton": "Continue",
+ "addTokenManually": "Add token manually",
+ "addFolder": "Add folder",
+ "searchTokens": "Search tokens",
+ "closeSearchTokens": "Close search",
+ "increaseCounter": "Increase counter",
+ "copyOTPToClipboard": "Copy OTP to clipboard",
+ "licenses": "Licenses",
+ "optionalMessage": "Optional message",
+ "confirmation": "Confirmation",
+ "askLogSendedDescription": "Did you send the log, and do you want to clear it now?",
+ "algorithmUnsupported": "The algorithm {algorithm} is not supported",
+ "@algorithmUnsupported": {
+ "placeholders": {
+ "algorithm": {
+ "example": "MD5"
+ }
+ }
+ },
+ "thisAppIsOpenSource": "This Application is Open Source\nVisit us on GitHub",
+ "importExportTokens": "Import/Export tokens",
+ "exportNonPrivacyIDEATokens": "Export non-privacyIDEA tokens",
+ "selectTokensToExport": "{count, plural, zero{} one{Select token to export} other{Select tokens to export}}",
+ "noTokensToExport": "No tokens to export",
+ "exportAllTokens": "Export all tokens",
+ "export": "Export",
+ "exportingTokens": "Exporting tokens...",
+ "exportTokens": "Export tokens",
+ "enterPasswordToEncrypt": "Enter a password to encrypt the tokens. This password will be required to import the tokens.",
+ "exportLockedTokenReason": "Please authenticate to export locked tokens.",
+ "fileSavedToDownloadsFolder": "File saved to Downloads folder",
+ "errorSavingFile": "Saving to file failed",
+ "toFile": "To file",
+ "asQrCode": "As QR code",
+ "scanThisQrWithNewDevice": "Scan this QR code with your new device to import the token.",
+ "oneMore": "One more",
+ "done": "Done",
+ "confirmPassword": "Confirm password",
+ "secretIsRequired": "Secret is required",
+ "tokenDataParseError": "Token data could not be parsed",
+ "missingRequiredParameter": "Value for parameter [{counter}] is required and is missing",
+ "@missingRequiredParameter": {
+ "placeholders": {
+ "counter": {
+ "example": "counter"
+ }
+ }
+ },
+ "invalidValueForParameter": "[{value}] is not a valid value for uri parameter [parameter].",
+ "@invalidValueForParameter": {
+ "placeholders": {
+ "value": {
+ "example": "abc"
+ },
+ "parameter": {
+ "example": "number"
+ }
+ }
+ },
+ "unsupported": "The {name} [{value}] is not supported by this version of the app.",
+ "@unsupported": {
+ "placeholders": {
+ "name": {
+ "example": "piauth version"
+ },
+ "value": {
+ "example": "5"
+ }
+ }
}
}
\ No newline at end of file
diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb
index 578fe5cd9..702a7a056 100644
--- a/lib/l10n/app_es.arb
+++ b/lib/l10n/app_es.arb
@@ -161,6 +161,12 @@
"@systemTheme": {
"description": "The systems theme."
},
+ "someTokensDoNotSupportPolling": "Algunos tokens están obsoletos y no admiten la consulta activa para la autenticación mediante mensaje push.",
+ "@someTokensDoNotSupportPolling": {
+ "description": "Tells the user, that the following tokens do not support polling.",
+ "type": "text",
+ "placeholders": {}
+ },
"enablePolling": "Activar polling",
"@enablePolling": {
"description": "Name of the setting switch that enables polling."
@@ -532,6 +538,7 @@
"invalidQrScan": "El código QR escaneado no es una copia de seguridad válida de {appName}",
"invalidQrFile": "El archivo seleccionado no contiene un código QR válido de {appName}",
"invalidLink": "El enlace introducido no es un token válido de {appName}, o no es compatible",
+ "importFailedToken": "{count, plural, zero{No token Fallo al importar.} one{Error al importar un token.} other{Error al importar {count} tokens.}}",
"importExistingToken": "{count, plural, zero{No se ha encontrado ningún token que ya esté en la aplicación.} one{Se ha encontrado un token que ya existe en la aplicación.} other{Se han encontrado {count} tokens que ya están en la aplicación.}}",
"importConflictToken": "{count, plural, zero{No hay conflicto con tokens que ya existen.} one{Hay un conflicto con tokens que ya existen.\nPor favor, seleccione cuál le gustaría conservar.} other{Hay un conflicto con tokens que ya existen.\nPor favor, seleccione cuál le gustaría conservar.}}",
"importNewToken": "{count, plural, zero{No se ha encontrado un nuevo token.} one{Se ha encontrado un nuevo token que se importará.} other{Se ha encontrado un nuevo token {count} que se importará.}}",
@@ -541,6 +548,9 @@
"importHintAegisLink": "Introduzca el enlace que recibe al transferir entradas desde Aegis",
"importHintGoogleQrScan": "Escanea el código QR que recibes al exportar tus cuentas desde Google Authenticator",
"importHintGoogleQrFile": "Selecciona un archivo de imagen con el código QR que recibes al exportar tus cuentas desde Google Authenticator.\n!! Tenga en cuenta que no es seguro guardar el código QR en su dispositivo, ya que los tokens no están cifrados !!",
+ "importHintAuthenticatorProFile": "Para crear una copia de seguridad de la aplicación Authenticator Pro, vaya a la configuración y pulse en \"Copia de seguridad automática\". Seleccione una ubicación de almacenamiento y establezca una contraseña. A continuación, pulse \"Hacer copia de seguridad ahora\" para exportar los tokens.",
+ "importHintFreeOtpPlusQrScan": "Escanea el código QR que recibes al pulsar los tres puntos en el azulejo de la ficha y selecciona \"Compartir código QR\".",
+ "importHintFreeOtpPlusFile": "Para crear una copia de seguridad de la app FreeOTP+, pulse los tres puntos de la esquina superior derecha y seleccione \"Exportar\". Puede elegir entre los formatos JSON y URI. Recomendamos eliminar la copia de seguridad después de importarla, ya que no está cifrada.",
"qrFileDecodeError": "No fue posible decodificar el código QR de la imagen seleccionada, por favor utilice el escáner de código QR en su lugar.",
"tokenLink": "Enlace token",
"feedback": "Comentarios",
@@ -571,5 +581,55 @@
"example": "GitHub"
}
}
- }
+ },
+ "errorUnlinkingPushToken": "Error al desvincular el token push {label}",
+ "@errorUnlinkingPushToken": {
+ "description": "Error message when unlinking a push token failed.",
+ "placeholders": {
+ "label": {
+ "example": "PUSH1234A"
+ }
+ }
+ },
+ "pleaseSyncManuallyWhenNetworkIsAvailable": "Por favor, sincronice los tokens push manualmente a través de los ajustes cuando haya una conexión de red disponible.",
+ "pushTokens": "Push Tokens",
+ "continueButton": "Continue",
+ "addTokenManually": "Añadir token manualmente",
+ "addFolder": "Añadir carpeta",
+ "searchTokens": "Buscar tokens",
+ "closeSearchTokens": "Cerrar búsqueda",
+ "increaseCounter": "Incrementar contador",
+ "copyOTPToClipboard": "Copiar OTP al portapapeles",
+ "licenses": "Licencias",
+ "optionalMessage": "Mensaje opcional",
+ "confirmation": "confirmación",
+ "askLogSendedDescription": "¿Ha enviado el registro y desea borrarlo ahora?",
+ "algorithmUnsupported": "El algoritmo {algorithm} no es compatible",
+ "@algorithmUnsupported": {
+ "placeholders": {
+ "algorithm": {
+ "example": "MD5"
+ }
+ }
+ },
+ "thisAppIsOpenSource": "Esta aplicación es de código abierto\nVisítanos en GitHub",
+ "invalidArgument": "{argument} no es un valor válido para {type}",
+ "importExportTokens": "Importar/Exportar tokens",
+ "exportNonPrivacyIDEATokens": "Exportar tokens no privacyIDEA",
+ "selectTokensToExport": "{count, plural, zero{} one{Seleccionar token para exportar} other{Seleccionar tokens para exportar}}",
+ "noTokensToExport": "No hay tokens para exportar",
+ "exportAllTokens": "Exportar todos los tokens",
+ "export": "Exportar",
+ "exportingTokens": "Exportando tokens...",
+ "exportTokens": "Exportar tokens",
+ "enterPasswordToEncrypt": "Ingrese una contraseña para cifrar los tokens. Esta contraseña será necesaria para importar los tokens.",
+ "exportLockedTokenReason": "Por favor, autentíquese para exportar tokens bloqueados.",
+ "fileSavedToDownloadsFolder": "Archivo guardado en la carpeta de descargas",
+ "errorSavingFile": "Error al guardar el archivo",
+ "toFile": "A archivo",
+ "asQrCode": "Como código QR",
+ "scanThisQrWithNewDevice": "Escanee este código QR con su nuevo dispositivo para importar el token.",
+ "oneMore": "Uno más",
+ "done": "Hecho",
+ "confirmPassword": "Confirmar contraseña"
}
\ No newline at end of file
diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb
index 772b34fba..c6962a79d 100644
--- a/lib/l10n/app_fr.arb
+++ b/lib/l10n/app_fr.arb
@@ -163,6 +163,12 @@
"@systemTheme": {
"description": "The systems theme."
},
+ "someTokensDoNotSupportPolling": "Certains jetons sont obsolètes et ne supportent pas l'interrogation due serveur.",
+ "@someTokensDoNotSupportPolling": {
+ "description": "Tells the user, that the following tokens do not support polling.",
+ "type": "text",
+ "placeholders": {}
+ },
"enablePolling": "Activer l'interrogation du serveur.",
"@enablePolling": {
"description": "Name of the setting switch that enables polling."
@@ -537,6 +543,7 @@
"invalidQrScan": "Le code QR scanné n'est pas une sauvegarde valide de {appName}",
"invalidQrFile": "Le fichier sélectionné ne contient pas de code QR valide de {appName}",
"invalidLink": "Le lien saisi n'est pas un jeton valide de {appName}, ou il n'est pas pris en charge",
+ "importFailedToken": "{count, plural, zero{Pas de jeton Échec de l'importation.} one{Échec de l'importation d'un jeton.} other{Échec de l'importation des jetons {count}.}}",
"importExistingToken": "{count, plural, zero{Aucun jeton déjà présent dans l'application n'a été trouvé.} one{Un jeton qui existe déjà dans l'application a été trouvé.} other{Des jetons {count} déjà présents dans l'application ont été trouvés.}}",
"importConflictToken": "{count, plural, zero{Il n'y a pas de conflit avec des tokens déjà existants.} one{Il y a un conflit avec des tokens déjà existants.\nVeuillez choisir celui que vous voulez garder.} other{Il y a un conflit avec des tokens déjà existants.\nVeuillez choisir celui que vous voulez garder.}}",
"importNewToken": "{count, plural, zero{Aucun nouveau token n'a été trouvé.} one{Un nouveau token a été trouvé et sera importé.} other{Aucun {count} nouveau token a été trouvé et sera importé.}}",
@@ -546,6 +553,9 @@
"importHintAegisLink": "Saisissez le lien que vous recevez lorsque vous transférez des entrées depuis Aegis",
"importHintGoogleQrScan": "Scannez le code QR que vous recevez lorsque vous exportez vos comptes depuis Google Authenticator",
"importHintGoogleQrFile": "Sélectionnez un fichier image avec le code QR que vous obtenez lorsque vous exportez vos comptes depuis Google Authenticator.\n!! Notez qu'il n'est pas sûr d'enregistrer le code QR sur votre appareil, car les jetons ne sont pas cryptés !!",
+ "importHintAuthenticatorProFile": "Pour créer une sauvegarde de l'application Authenticator Pro, accédez aux paramètres et appuyez sur \"Sauvegarde automatique\". Sélectionnez un emplacement de stockage et définissez un mot de passe. Puis appuyez sur \"Sauvegarder maintenant\" pour exporter les tokens.",
+ "importHintFreeOtpPlusQrScan": "Scannez le code QR que vous recevez lorsque vous appuyez sur les trois points dans la tuile du jeton et sélectionnez \"Partager le code QR\".",
+ "importHintFreeOtpPlusFile": "Pour créer une sauvegarde de l'application FreeOTP+, appuyez sur les trois points dans le coin supérieur droit et sélectionnez \"Exporter\". Vous pouvez choisir entre les formats JSON et URI. Nous recommandons de supprimer la sauvegarde après l'avoir importée, car elle n'est pas cryptée.",
"qrFileDecodeError": "Il n'a pas été possible de décoder le code QR à partir de l'image sélectionnée, veuillez utiliser le scanner de code QR à la place",
"tokenLink": "Lien vers le token",
"feedback": "Retour d'information",
@@ -576,5 +586,55 @@
"exemple": "GitHub"
}
}
- }
+ },
+ "errorUnlinkingPushToken": "Echec du découplage du push token {label}",
+ "@errorUnlinkingPushToken": {
+ "description": "Error message when unlinking a push token failed.",
+ "placeholders": {
+ "label": {
+ "example": "PUSH1234A"
+ }
+ }
+ },
+ "pleaseSyncManuallyWhenNetworkIsAvailable": "Veuillez synchroniser manuellement les jetons Push via les paramètres lorsqu'une connexion réseau est disponible",
+ "pushTokens": "Push Tokens",
+ "continueButton": "Continue",
+ "addTokenManually": "Add token manually",
+ "addFolder": "Ajouter un dossier",
+ "searchTokens": "Jetons de recherche",
+ "closeSearchTokens": "Fermer la recherche",
+ "increaseCounter": "Augmenter le compteur",
+ "copyOTPToClipboard": "Copier l'OTP dans le presse-papiers",
+ "licenses": "Licences",
+ "optionalMessage": "Message optionnel",
+ "confirmation": "Confirmation",
+ "askLogSendedDescription": "Avez-vous envoyé le journal et voulez-vous l'effacer maintenant ?",
+ "algorithmUnsupported": "L'algorithme {algorithm} n'est pas pris en charge",
+ "@algorithmUnsupported": {
+ "placeholders": {
+ "algorithm": {
+ "example": "MD5"
+ }
+ }
+ },
+ "thisAppIsOpenSource": "Cette application est open source\nRendez-nous visite sur GitHub",
+ "invalidArgument": "{argument} n'est pas une valeur valide pour {type}",
+ "importExportTokens": "Importer/Exporter les jetons",
+ "exportNonPrivacyIDEATokens": "Exporter les jetons non privacyIDEA",
+ "selectTokensToExport": "{count, plural, zero{} one{Sélectionner le jeton à exporter} other{Sélectionner les jetons à exporter}}",
+ "noTokensToExport": "Aucun jeton à exporter",
+ "exportAllTokens": "Exporter tous les jetons",
+ "export": "Exporter",
+ "exportingTokens": "Exportation des jetons en cours...",
+ "exportTokens": "Exporter les jetons",
+ "enterPasswordToEncrypt": "Entrez un mot de passe pour chiffrer les jetons. Ce mot de passe sera requis pour importer les jetons.",
+ "exportLockedTokenReason": "Veuillez vous authentifier pour exporter les jetons verrouillés.",
+ "fileSavedToDownloadsFolder": "Fichier enregistré dans le dossier Téléchargements",
+ "errorSavingFile": "Erreur lors de l'enregistrement du fichier",
+ "toFile": "Vers fichier",
+ "asQrCode": "Sous forme de code QR",
+ "scanThisQrWithNewDevice": "Scannez ce code QR avec votre nouvel appareil pour importer le jeton.",
+ "oneMore": "Encore un",
+ "done": "Terminé",
+ "confirmPassword": "Confirmer le mot de passe"
}
\ No newline at end of file
diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart
index 8b175eb7c..f608e8c83 100644
--- a/lib/l10n/app_localizations.dart
+++ b/lib/l10n/app_localizations.dart
@@ -367,6 +367,12 @@ abstract class AppLocalizations {
/// **'Use device\'s theme'**
String get systemTheme;
+ /// Tells the user, that the following tokens do not support polling.
+ ///
+ /// In en, this message translates to:
+ /// **'Some of the tokens are outdated and do not support polling'**
+ String get someTokensDoNotSupportPolling;
+
/// Name of the setting switch that enables polling.
///
/// In en, this message translates to:
@@ -1243,6 +1249,12 @@ abstract class AppLocalizations {
/// **'The link entered is not a valid token of {appName}, or it is not supported.'**
String invalidLink(Object appName);
+ /// No description provided for @importFailedToken.
+ ///
+ /// In en, this message translates to:
+ /// **'{count, plural, zero{No token Failed to import.} one{Failed to import a token.} other{Failed to import {count} tokens.}}'**
+ String importFailedToken(num count);
+
/// No description provided for @importExistingToken.
///
/// In en, this message translates to:
@@ -1252,7 +1264,7 @@ abstract class AppLocalizations {
/// No description provided for @importConflictToken.
///
/// In en, this message translates to:
- /// **'{count, plural, zero{There is no conflict with existing tokens.} one{There is a conflict with an existing token.\nPlease choose which one you want to keep.} other{There are conflicts with existing tokens.\nPlease choose which one you want to keep.}}'**
+ /// **'{count, plural, zero{There is no conflict with existing tokens.} one{There is a conflict with existing tokens.\nPlease select which one you would like to keep.} other{There are conflicts with existing tokens.\nPlease select the tokens you wish to keep.}}'**
String importConflictToken(num count);
/// No description provided for @importNewToken.
@@ -1297,6 +1309,24 @@ abstract class AppLocalizations {
/// **'Select an image file with the QR code you receive when you export your accounts from Google Authenticator.\n!! Note that it is not safe to save the QR code on your device as the tokens are not encrypted !!'**
String get importHintGoogleQrFile;
+ /// No description provided for @importHintAuthenticatorProFile.
+ ///
+ /// In en, this message translates to:
+ /// **'To create a backup of the Authenticator Pro app, navigate to the settings and tap on \"Auto backup\". Select a storage location and set a password. Then press \"Back up now\" to export the tokens.'**
+ String get importHintAuthenticatorProFile;
+
+ /// No description provided for @importHintFreeOtpPlusQrScan.
+ ///
+ /// In en, this message translates to:
+ /// **'Scan the QR code you receive when you press the three dots in the tile of the token and select \"Share QR code\".'**
+ String get importHintFreeOtpPlusQrScan;
+
+ /// No description provided for @importHintFreeOtpPlusFile.
+ ///
+ /// In en, this message translates to:
+ /// **'To create a backup of the FreeOTP+ app, tap on the three dots in the upper right corner and select \"Export\". You can choose between JSON and URI format. We recommend to delete the backup after importing it, because it is not encrypted.'**
+ String get importHintFreeOtpPlusFile;
+
/// No description provided for @qrFileDecodeError.
///
/// In en, this message translates to:
@@ -1404,6 +1434,240 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'Sent by {issuer} for your account: \"{account}\"'**
String requestInfo(Object issuer, Object account);
+
+ /// Error message when unlinking a push token failed.
+ ///
+ /// In en, this message translates to:
+ /// **'Failed to unlink the push token {label}.'**
+ String errorUnlinkingPushToken(Object label);
+
+ /// No description provided for @pleaseSyncManuallyWhenNetworkIsAvailable.
+ ///
+ /// In en, this message translates to:
+ /// **'Please synchronize the push tokens manually via the settings when a network connection is available.'**
+ String get pleaseSyncManuallyWhenNetworkIsAvailable;
+
+ /// No description provided for @pushTokens.
+ ///
+ /// In en, this message translates to:
+ /// **'Push Tokens'**
+ String get pushTokens;
+
+ /// No description provided for @continueButton.
+ ///
+ /// In en, this message translates to:
+ /// **'Continue'**
+ String get continueButton;
+
+ /// No description provided for @addTokenManually.
+ ///
+ /// In en, this message translates to:
+ /// **'Add token manually'**
+ String get addTokenManually;
+
+ /// No description provided for @addFolder.
+ ///
+ /// In en, this message translates to:
+ /// **'Add folder'**
+ String get addFolder;
+
+ /// No description provided for @searchTokens.
+ ///
+ /// In en, this message translates to:
+ /// **'Search tokens'**
+ String get searchTokens;
+
+ /// No description provided for @closeSearchTokens.
+ ///
+ /// In en, this message translates to:
+ /// **'Close search'**
+ String get closeSearchTokens;
+
+ /// No description provided for @increaseCounter.
+ ///
+ /// In en, this message translates to:
+ /// **'Increase counter'**
+ String get increaseCounter;
+
+ /// No description provided for @copyOTPToClipboard.
+ ///
+ /// In en, this message translates to:
+ /// **'Copy OTP to clipboard'**
+ String get copyOTPToClipboard;
+
+ /// No description provided for @licenses.
+ ///
+ /// In en, this message translates to:
+ /// **'Licenses'**
+ String get licenses;
+
+ /// No description provided for @optionalMessage.
+ ///
+ /// In en, this message translates to:
+ /// **'Optional message'**
+ String get optionalMessage;
+
+ /// No description provided for @confirmation.
+ ///
+ /// In en, this message translates to:
+ /// **'Confirmation'**
+ String get confirmation;
+
+ /// No description provided for @askLogSendedDescription.
+ ///
+ /// In en, this message translates to:
+ /// **'Did you send the log, and do you want to clear it now?'**
+ String get askLogSendedDescription;
+
+ /// No description provided for @algorithmUnsupported.
+ ///
+ /// In en, this message translates to:
+ /// **'The algorithm {algorithm} is not supported'**
+ String algorithmUnsupported(Object algorithm);
+
+ /// No description provided for @thisAppIsOpenSource.
+ ///
+ /// In en, this message translates to:
+ /// **'This Application is Open Source\nVisit us on GitHub'**
+ String get thisAppIsOpenSource;
+
+ /// No description provided for @importExportTokens.
+ ///
+ /// In en, this message translates to:
+ /// **'Import/Export tokens'**
+ String get importExportTokens;
+
+ /// No description provided for @exportNonPrivacyIDEATokens.
+ ///
+ /// In en, this message translates to:
+ /// **'Export non-privacyIDEA tokens'**
+ String get exportNonPrivacyIDEATokens;
+
+ /// No description provided for @selectTokensToExport.
+ ///
+ /// In en, this message translates to:
+ /// **'{count, plural, zero{} one{Select token to export} other{Select tokens to export}}'**
+ String selectTokensToExport(num count);
+
+ /// No description provided for @noTokensToExport.
+ ///
+ /// In en, this message translates to:
+ /// **'No tokens to export'**
+ String get noTokensToExport;
+
+ /// No description provided for @exportAllTokens.
+ ///
+ /// In en, this message translates to:
+ /// **'Export all tokens'**
+ String get exportAllTokens;
+
+ /// No description provided for @export.
+ ///
+ /// In en, this message translates to:
+ /// **'Export'**
+ String get export;
+
+ /// No description provided for @exportingTokens.
+ ///
+ /// In en, this message translates to:
+ /// **'Exporting tokens...'**
+ String get exportingTokens;
+
+ /// No description provided for @exportTokens.
+ ///
+ /// In en, this message translates to:
+ /// **'Export tokens'**
+ String get exportTokens;
+
+ /// No description provided for @enterPasswordToEncrypt.
+ ///
+ /// In en, this message translates to:
+ /// **'Enter a password to encrypt the tokens. This password will be required to import the tokens.'**
+ String get enterPasswordToEncrypt;
+
+ /// No description provided for @exportLockedTokenReason.
+ ///
+ /// In en, this message translates to:
+ /// **'Please authenticate to export locked tokens.'**
+ String get exportLockedTokenReason;
+
+ /// No description provided for @fileSavedToDownloadsFolder.
+ ///
+ /// In en, this message translates to:
+ /// **'File saved to Downloads folder'**
+ String get fileSavedToDownloadsFolder;
+
+ /// No description provided for @errorSavingFile.
+ ///
+ /// In en, this message translates to:
+ /// **'Saving to file failed'**
+ String get errorSavingFile;
+
+ /// No description provided for @toFile.
+ ///
+ /// In en, this message translates to:
+ /// **'To file'**
+ String get toFile;
+
+ /// No description provided for @asQrCode.
+ ///
+ /// In en, this message translates to:
+ /// **'As QR code'**
+ String get asQrCode;
+
+ /// No description provided for @scanThisQrWithNewDevice.
+ ///
+ /// In en, this message translates to:
+ /// **'Scan this QR code with your new device to import the token.'**
+ String get scanThisQrWithNewDevice;
+
+ /// No description provided for @oneMore.
+ ///
+ /// In en, this message translates to:
+ /// **'One more'**
+ String get oneMore;
+
+ /// No description provided for @done.
+ ///
+ /// In en, this message translates to:
+ /// **'Done'**
+ String get done;
+
+ /// No description provided for @confirmPassword.
+ ///
+ /// In en, this message translates to:
+ /// **'Confirm password'**
+ String get confirmPassword;
+
+ /// No description provided for @secretIsRequired.
+ ///
+ /// In en, this message translates to:
+ /// **'Secret is required'**
+ String get secretIsRequired;
+
+ /// No description provided for @tokenDataParseError.
+ ///
+ /// In en, this message translates to:
+ /// **'Token data could not be parsed'**
+ String get tokenDataParseError;
+
+ /// No description provided for @missingRequiredParameter.
+ ///
+ /// In en, this message translates to:
+ /// **'Value for parameter [{counter}] is required and is missing'**
+ String missingRequiredParameter(Object counter);
+
+ /// No description provided for @invalidValueForParameter.
+ ///
+ /// In en, this message translates to:
+ /// **'[{value}] is not a valid value for uri parameter [parameter].'**
+ String invalidValueForParameter(Object value, Object parameter);
+
+ /// No description provided for @unsupported.
+ ///
+ /// In en, this message translates to:
+ /// **'The {name} [{value}] is not supported by this version of the app.'**
+ String unsupported(Object name, Object value);
}
class _AppLocalizationsDelegate extends LocalizationsDelegate {
diff --git a/lib/l10n/app_localizations_cs.dart b/lib/l10n/app_localizations_cs.dart
index af40ff1a4..f5ec56d65 100644
--- a/lib/l10n/app_localizations_cs.dart
+++ b/lib/l10n/app_localizations_cs.dart
@@ -142,6 +142,9 @@ class AppLocalizationsCs extends AppLocalizations {
@override
String get systemTheme => 'Použít nastavení systému';
+ @override
+ String get someTokensDoNotSupportPolling => 'Některé tokeny jsou zastaralé a nepodporují polling';
+
@override
String get enablePolling => 'Povolit polling';
@@ -606,6 +609,18 @@ class AppLocalizationsCs extends AppLocalizations {
return 'Zadaný odkaz není platným tokenem $appName nebo není podporován.';
}
+ @override
+ String importFailedToken(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Nepodařilo se importovat $count tokenů.',
+ one: 'Nepodařilo se importovat token.',
+ zero: 'Žádný token Nepodařilo se importovat.',
+ );
+ return '$_temp0';
+ }
+
@override
String importExistingToken(num count) {
String _temp0 = intl.Intl.pluralLogic(
@@ -660,6 +675,15 @@ class AppLocalizationsCs extends AppLocalizations {
@override
String get importHintGoogleQrFile => 'Vyberte obrazový soubor s QR kódem, který obdržíte při exportu účtů z Google Authenticator.\n!! Upozorňujeme, že není bezpečné ukládat QR kód do zařízení, protože tokeny nejsou šifrovány !!';
+ @override
+ String get importHintAuthenticatorProFile => 'Chcete-li vytvořit zálohu aplikace Authenticator Pro, přejděte do nastavení a klepněte na položku \"Automatické zálohování\". Vyberte umístění úložiště a nastavte heslo. Poté stiskněte \"Zálohovat nyní\" a exportujte tokeny.';
+
+ @override
+ String get importHintFreeOtpPlusQrScan => 'Naskenujte QR kód, který obdržíte po stisknutí tří teček na dlaždici tokenu, a vyberte možnost \"Sdílet QR kód\".';
+
+ @override
+ String get importHintFreeOtpPlusFile => 'Chcete-li vytvořit zálohu aplikace FreeOTP+, klepněte na tři tečky v pravém horním rohu a vyberte možnost \"Exportovat\". Můžete si vybrat mezi formátem JSON a URI. Zálohu doporučujeme po importu odstranit, protože není šifrovaná.';
+
@override
String get qrFileDecodeError => 'Z vybraného obrázku nebylo možné dekódovat QR kód, použijte prosím místo toho skener QR kódů.';
@@ -715,4 +739,140 @@ class AppLocalizationsCs extends AppLocalizations {
String requestInfo(Object issuer, Object account) {
return 'Odesláno $issuer pro váš účet: \"$account\"';
}
+
+ @override
+ String errorUnlinkingPushToken(Object label) {
+ return 'Nepodařilo se odlinkovat push token $label.';
+ }
+
+ @override
+ String get pleaseSyncManuallyWhenNetworkIsAvailable => 'Synchronizujte prosím push tokeny ručně prostřednictvím nastavení, když je k dispozici síťové připojení.';
+
+ @override
+ String get pushTokens => 'Žetony Push';
+
+ @override
+ String get continueButton => 'Pokračovat';
+
+ @override
+ String get addTokenManually => 'Přidat token ručně';
+
+ @override
+ String get addFolder => 'Přidat složku';
+
+ @override
+ String get searchTokens => 'Hledat tokeny';
+
+ @override
+ String get closeSearchTokens => 'Zavřít vyhledávání';
+
+ @override
+ String get increaseCounter => 'Zvýšit počítadla';
+
+ @override
+ String get copyOTPToClipboard => 'Zkopírovat OTP do schránky';
+
+ @override
+ String get licenses => 'Licence';
+
+ @override
+ String get optionalMessage => 'Volitelná zpráva';
+
+ @override
+ String get confirmation => 'Potvrzení';
+
+ @override
+ String get askLogSendedDescription => 'Odeslali jste protokol a chcete jej nyní vymazat?';
+
+ @override
+ String algorithmUnsupported(Object algorithm) {
+ return 'Algoritmus $algorithm není podporován';
+ }
+
+ @override
+ String get thisAppIsOpenSource => 'Tato aplikace má otevřený zdrojový kód\nNavštivte nás na GitHub';
+
+ @override
+ String get importExportTokens => 'Import/Exportovat žetony';
+
+ @override
+ String get exportNonPrivacyIDEATokens => 'Exportovat ne-privacyIDEA žetony';
+
+ @override
+ String selectTokensToExport(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Vyberte žetony k exportu',
+ one: 'Vyberte žeton k exportu',
+ zero: '',
+ );
+ return '$_temp0';
+ }
+
+ @override
+ String get noTokensToExport => 'Žádné žetony k exportu';
+
+ @override
+ String get exportAllTokens => 'Exportovat všechny žetony';
+
+ @override
+ String get export => 'Export';
+
+ @override
+ String get exportingTokens => 'Probíhá export žetonů...';
+
+ @override
+ String get exportTokens => 'Exportovat žetony';
+
+ @override
+ String get enterPasswordToEncrypt => 'Zadejte heslo pro šifrování žetonů. Toto heslo bude vyžadováno k importu žetonů.';
+
+ @override
+ String get exportLockedTokenReason => 'Prosím, ověřte se, abyste mohli exportovat uzamčené žetony.';
+
+ @override
+ String get fileSavedToDownloadsFolder => 'Soubor uložen do složky Stažené soubory';
+
+ @override
+ String get errorSavingFile => 'Chyba při ukládání souboru';
+
+ @override
+ String get toFile => 'Do souboru';
+
+ @override
+ String get asQrCode => 'Jako QR kód';
+
+ @override
+ String get scanThisQrWithNewDevice => 'Naskenujte tento QR kód svým novým zařízením pro import žetonu.';
+
+ @override
+ String get oneMore => 'Ještě jeden';
+
+ @override
+ String get done => 'Hotovo';
+
+ @override
+ String get confirmPassword => 'Potvrďte heslo';
+
+ @override
+ String get secretIsRequired => 'Secret is required';
+
+ @override
+ String get tokenDataParseError => 'Token data could not be parsed';
+
+ @override
+ String missingRequiredParameter(Object counter) {
+ return 'Value for parameter [$counter] is required and is missing';
+ }
+
+ @override
+ String invalidValueForParameter(Object value, Object parameter) {
+ return '[$value] is not a valid value for uri parameter [parameter].';
+ }
+
+ @override
+ String unsupported(Object name, Object value) {
+ return 'The $name [$value] is not supported by this version of the app.';
+ }
}
diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart
index bab37b6ca..5109fb4d8 100644
--- a/lib/l10n/app_localizations_de.dart
+++ b/lib/l10n/app_localizations_de.dart
@@ -28,7 +28,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get patchNotesV4_3_0NewFeatures2 => 'Feedback-Option zu den Einstellungen hinzugefügt.';
@override
- String get patchNotesV4_3_0NewFeatures3 => 'Push-Tokens können jetzt aus der Token-Liste ausgeblendet werden.';
+ String get patchNotesV4_3_0NewFeatures3 => 'Push-Token können jetzt aus der Token-Liste ausgeblendet werden.';
@override
String get patchNotesV4_3_0NewFeatures4 => 'Es wurden Einführungen hinzugefügt, um neuen Benutzern den Einstieg zu erleichtern.';
@@ -142,6 +142,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get systemTheme => 'Nutze Farbschema des Geräts';
+ @override
+ String get someTokensDoNotSupportPolling => 'Einige der Token sind veraltet und unterstützen keine aktiven Anfragen';
+
@override
String get enablePolling => 'Aktives Stellen von Push-Anfragen';
@@ -606,6 +609,18 @@ class AppLocalizationsDe extends AppLocalizations {
return 'Der eingegebene Link ist kein gültiger Token von $appName, oder er wird nicht unterstützt.';
}
+ @override
+ String importFailedToken(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Der Import von $count Token ist fehlgeschlagen.',
+ one: 'Importieren eines Tokens fehlgeschlagen.',
+ zero: 'Kein Token konnte nicht importiert werden.',
+ );
+ return '$_temp0';
+ }
+
@override
String importExistingToken(num count) {
String _temp0 = intl.Intl.pluralLogic(
@@ -623,8 +638,8 @@ class AppLocalizationsDe extends AppLocalizations {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
- other: 'Es besteht ein Konflikt mit bereits existierenden Token.\nBitte wählen Sie aus, welches Sie behalten möchten.',
- one: 'Es besteht ein Konflikt mit bereits existierenden Token.\nBitte wählen Sie aus, welches Sie behalten möchten.',
+ other: 'Es bestehen Konflikte mit bereits vorhandenen Token.\nBitte wählen Sie die Token aus, die Sie behalten möchten.',
+ one: 'Es besteht ein Konflikt mit bereits vorhandenen Token.\nBitte wählen Sie aus, welches Sie behalten möchten.',
zero: 'Es besteht kein Konflikt mit bereits existierenden Token.',
);
return '$_temp0';
@@ -660,6 +675,15 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get importHintGoogleQrFile => 'Wählen Sie eine Bilddatei mit dem QR-Code, den Sie erhalten, wenn Sie Ihre Konten aus dem Google Authenticator exportieren.\n!! Der QR-Code enthält die Token in unverschlüsselter Form. Es ist deshalb nicht sicher, diesen länger als nötig aufzubewahren !!';
+ @override
+ String get importHintAuthenticatorProFile => 'Um ein Backup der Authenticator Pro-App zu erstellen navigieren Sie zu den Einstellungen und tippen Sie auf \"Automatische Sicherung\". Wählen Sie einen Speicherort und setzen Sie ein Passwort. Anschließend drücken Sie auf \"Jetzt sichern\" um die Token zu exportieren.';
+
+ @override
+ String get importHintFreeOtpPlusQrScan => 'Scannen Sie den QR-Code, den Sie erhalten, wenn Sie auf die drei Punkte in der Kachel des Tokens drücken, und wählen Sie \"QR-Code teilen\".';
+
+ @override
+ String get importHintFreeOtpPlusFile => 'Um ein Backup der FreeOTP+ App zu erstellen, tippen Sie auf die drei Punkte in der oberen rechten Ecke und wählen Sie \"Exportieren\". Sie können zwischen dem JSON- und dem URI-Format wählen. Wir empfehlen, das Backup nach dem Importieren zu löschen, da es nicht verschlüsselt ist.';
+
@override
String get qrFileDecodeError => 'Es war nicht möglich, den QR-Code aus dem ausgewählten Bild zu dekodieren. Bitte verwenden Sie stattdessen den QR-Code-Scanner.';
@@ -715,4 +739,140 @@ class AppLocalizationsDe extends AppLocalizations {
String requestInfo(Object issuer, Object account) {
return 'Gesendet von $issuer für Ihr Konto: \"$account\"';
}
+
+ @override
+ String errorUnlinkingPushToken(Object label) {
+ return 'Entkoppeln des Push Tokens $label fehlgeschlagen.';
+ }
+
+ @override
+ String get pleaseSyncManuallyWhenNetworkIsAvailable => 'Bitte synchronisieren Sie die Push Token über die Einstellungen manuell, wenn eine Netzwerkverbindung verfügbar ist.';
+
+ @override
+ String get pushTokens => 'Push-Token';
+
+ @override
+ String get continueButton => 'Weiter';
+
+ @override
+ String get addTokenManually => 'Token manuell hinzufügen';
+
+ @override
+ String get addFolder => 'Ordner hinzufügen';
+
+ @override
+ String get searchTokens => 'Token suchen';
+
+ @override
+ String get closeSearchTokens => 'Suche schließen';
+
+ @override
+ String get increaseCounter => 'Zähler erhöhen';
+
+ @override
+ String get copyOTPToClipboard => 'OTP in die Zwischenablage kopieren';
+
+ @override
+ String get licenses => 'Lizenzen';
+
+ @override
+ String get optionalMessage => 'Optionale Nachricht';
+
+ @override
+ String get confirmation => 'Confirmation';
+
+ @override
+ String get askLogSendedDescription => 'Haben Sie das Protokoll gesendet, und möchten Sie es jetzt löschen?';
+
+ @override
+ String algorithmUnsupported(Object algorithm) {
+ return 'Der Algorithmus $algorithm wird nicht unterstützt';
+ }
+
+ @override
+ String get thisAppIsOpenSource => 'Diese App ist Open Source\nBesuchen Sie uns auf GitHub';
+
+ @override
+ String get importExportTokens => 'Token importieren/exportieren';
+
+ @override
+ String get exportNonPrivacyIDEATokens => 'Nicht-privacyIDEA-Token exportieren';
+
+ @override
+ String selectTokensToExport(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Wählen Sie die zu exportierenden Tokens aus',
+ one: 'Wählen Sie das zu exportierende Token aus',
+ zero: '',
+ );
+ return '$_temp0';
+ }
+
+ @override
+ String get noTokensToExport => 'Keine Tokens zum Exportieren';
+
+ @override
+ String get exportAllTokens => 'Alle Tokens exportieren';
+
+ @override
+ String get export => 'Exportieren';
+
+ @override
+ String get exportingTokens => 'Tokens werden exportiert...';
+
+ @override
+ String get exportTokens => 'Tokens exportieren';
+
+ @override
+ String get enterPasswordToEncrypt => 'Geben Sie ein Passwort ein, um die Tokens zu verschlüsseln. Dieses Passwort wird benötigt, um die Tokens zu importieren.';
+
+ @override
+ String get exportLockedTokenReason => 'Bitte authentifizieren Sie sich, um gesperrte Tokens zu exportieren.';
+
+ @override
+ String get fileSavedToDownloadsFolder => 'Datei wurde im Download-Ordner gespeichert';
+
+ @override
+ String get errorSavingFile => 'Fehler beim Speichern der Datei';
+
+ @override
+ String get toFile => 'In Datei';
+
+ @override
+ String get asQrCode => 'Als QR-Code';
+
+ @override
+ String get scanThisQrWithNewDevice => 'Scannen Sie diesen QR-Code mit Ihrem neuen Gerät, um das Token zu importieren.';
+
+ @override
+ String get oneMore => 'Noch eins';
+
+ @override
+ String get done => 'Fertig';
+
+ @override
+ String get confirmPassword => 'Passwort bestätigen';
+
+ @override
+ String get secretIsRequired => 'Secret is required';
+
+ @override
+ String get tokenDataParseError => 'Token data could not be parsed';
+
+ @override
+ String missingRequiredParameter(Object counter) {
+ return 'Value for parameter [$counter] is required and is missing';
+ }
+
+ @override
+ String invalidValueForParameter(Object value, Object parameter) {
+ return '[$value] is not a valid value for uri parameter [parameter].';
+ }
+
+ @override
+ String unsupported(Object name, Object value) {
+ return 'The $name [$value] is not supported by this version of the app.';
+ }
}
diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart
index ddd482bad..ca4f6163b 100644
--- a/lib/l10n/app_localizations_en.dart
+++ b/lib/l10n/app_localizations_en.dart
@@ -142,6 +142,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get systemTheme => 'Use device\'s theme';
+ @override
+ String get someTokensDoNotSupportPolling => 'Some of the tokens are outdated and do not support polling';
+
@override
String get enablePolling => 'Enable polling';
@@ -606,6 +609,18 @@ class AppLocalizationsEn extends AppLocalizations {
return 'The link entered is not a valid token of $appName, or it is not supported.';
}
+ @override
+ String importFailedToken(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Failed to import $count tokens.',
+ one: 'Failed to import a token.',
+ zero: 'No token Failed to import.',
+ );
+ return '$_temp0';
+ }
+
@override
String importExistingToken(num count) {
String _temp0 = intl.Intl.pluralLogic(
@@ -623,8 +638,8 @@ class AppLocalizationsEn extends AppLocalizations {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
- other: 'There are conflicts with existing tokens.\nPlease choose which one you want to keep.',
- one: 'There is a conflict with an existing token.\nPlease choose which one you want to keep.',
+ other: 'There are conflicts with existing tokens.\nPlease select the tokens you wish to keep.',
+ one: 'There is a conflict with existing tokens.\nPlease select which one you would like to keep.',
zero: 'There is no conflict with existing tokens.',
);
return '$_temp0';
@@ -660,6 +675,15 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get importHintGoogleQrFile => 'Select an image file with the QR code you receive when you export your accounts from Google Authenticator.\n!! Note that it is not safe to save the QR code on your device as the tokens are not encrypted !!';
+ @override
+ String get importHintAuthenticatorProFile => 'To create a backup of the Authenticator Pro app, navigate to the settings and tap on \"Auto backup\". Select a storage location and set a password. Then press \"Back up now\" to export the tokens.';
+
+ @override
+ String get importHintFreeOtpPlusQrScan => 'Scan the QR code you receive when you press the three dots in the tile of the token and select \"Share QR code\".';
+
+ @override
+ String get importHintFreeOtpPlusFile => 'To create a backup of the FreeOTP+ app, tap on the three dots in the upper right corner and select \"Export\". You can choose between JSON and URI format. We recommend to delete the backup after importing it, because it is not encrypted.';
+
@override
String get qrFileDecodeError => 'It was not possible to decode the QR code from the selected image, please use the QR code scanner instead.';
@@ -715,4 +739,140 @@ class AppLocalizationsEn extends AppLocalizations {
String requestInfo(Object issuer, Object account) {
return 'Sent by $issuer for your account: \"$account\"';
}
+
+ @override
+ String errorUnlinkingPushToken(Object label) {
+ return 'Failed to unlink the push token $label.';
+ }
+
+ @override
+ String get pleaseSyncManuallyWhenNetworkIsAvailable => 'Please synchronize the push tokens manually via the settings when a network connection is available.';
+
+ @override
+ String get pushTokens => 'Push Tokens';
+
+ @override
+ String get continueButton => 'Continue';
+
+ @override
+ String get addTokenManually => 'Add token manually';
+
+ @override
+ String get addFolder => 'Add folder';
+
+ @override
+ String get searchTokens => 'Search tokens';
+
+ @override
+ String get closeSearchTokens => 'Close search';
+
+ @override
+ String get increaseCounter => 'Increase counter';
+
+ @override
+ String get copyOTPToClipboard => 'Copy OTP to clipboard';
+
+ @override
+ String get licenses => 'Licenses';
+
+ @override
+ String get optionalMessage => 'Optional message';
+
+ @override
+ String get confirmation => 'Confirmation';
+
+ @override
+ String get askLogSendedDescription => 'Did you send the log, and do you want to clear it now?';
+
+ @override
+ String algorithmUnsupported(Object algorithm) {
+ return 'The algorithm $algorithm is not supported';
+ }
+
+ @override
+ String get thisAppIsOpenSource => 'This Application is Open Source\nVisit us on GitHub';
+
+ @override
+ String get importExportTokens => 'Import/Export tokens';
+
+ @override
+ String get exportNonPrivacyIDEATokens => 'Export non-privacyIDEA tokens';
+
+ @override
+ String selectTokensToExport(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Select tokens to export',
+ one: 'Select token to export',
+ zero: '',
+ );
+ return '$_temp0';
+ }
+
+ @override
+ String get noTokensToExport => 'No tokens to export';
+
+ @override
+ String get exportAllTokens => 'Export all tokens';
+
+ @override
+ String get export => 'Export';
+
+ @override
+ String get exportingTokens => 'Exporting tokens...';
+
+ @override
+ String get exportTokens => 'Export tokens';
+
+ @override
+ String get enterPasswordToEncrypt => 'Enter a password to encrypt the tokens. This password will be required to import the tokens.';
+
+ @override
+ String get exportLockedTokenReason => 'Please authenticate to export locked tokens.';
+
+ @override
+ String get fileSavedToDownloadsFolder => 'File saved to Downloads folder';
+
+ @override
+ String get errorSavingFile => 'Saving to file failed';
+
+ @override
+ String get toFile => 'To file';
+
+ @override
+ String get asQrCode => 'As QR code';
+
+ @override
+ String get scanThisQrWithNewDevice => 'Scan this QR code with your new device to import the token.';
+
+ @override
+ String get oneMore => 'One more';
+
+ @override
+ String get done => 'Done';
+
+ @override
+ String get confirmPassword => 'Confirm password';
+
+ @override
+ String get secretIsRequired => 'Secret is required';
+
+ @override
+ String get tokenDataParseError => 'Token data could not be parsed';
+
+ @override
+ String missingRequiredParameter(Object counter) {
+ return 'Value for parameter [$counter] is required and is missing';
+ }
+
+ @override
+ String invalidValueForParameter(Object value, Object parameter) {
+ return '[$value] is not a valid value for uri parameter [parameter].';
+ }
+
+ @override
+ String unsupported(Object name, Object value) {
+ return 'The $name [$value] is not supported by this version of the app.';
+ }
}
diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart
index 420cd7d7a..046d5d766 100644
--- a/lib/l10n/app_localizations_es.dart
+++ b/lib/l10n/app_localizations_es.dart
@@ -142,6 +142,9 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get systemTheme => 'Utilizar el tema del teléfono';
+ @override
+ String get someTokensDoNotSupportPolling => 'Algunos tokens están obsoletos y no admiten la consulta activa para la autenticación mediante mensaje push.';
+
@override
String get enablePolling => 'Activar polling';
@@ -606,6 +609,18 @@ class AppLocalizationsEs extends AppLocalizations {
return 'El enlace introducido no es un token válido de $appName, o no es compatible';
}
+ @override
+ String importFailedToken(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Error al importar $count tokens.',
+ one: 'Error al importar un token.',
+ zero: 'No token Fallo al importar.',
+ );
+ return '$_temp0';
+ }
+
@override
String importExistingToken(num count) {
String _temp0 = intl.Intl.pluralLogic(
@@ -660,6 +675,15 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get importHintGoogleQrFile => 'Selecciona un archivo de imagen con el código QR que recibes al exportar tus cuentas desde Google Authenticator.\n!! Tenga en cuenta que no es seguro guardar el código QR en su dispositivo, ya que los tokens no están cifrados !!';
+ @override
+ String get importHintAuthenticatorProFile => 'Para crear una copia de seguridad de la aplicación Authenticator Pro, vaya a la configuración y pulse en \"Copia de seguridad automática\". Seleccione una ubicación de almacenamiento y establezca una contraseña. A continuación, pulse \"Hacer copia de seguridad ahora\" para exportar los tokens.';
+
+ @override
+ String get importHintFreeOtpPlusQrScan => 'Escanea el código QR que recibes al pulsar los tres puntos en el azulejo de la ficha y selecciona \"Compartir código QR\".';
+
+ @override
+ String get importHintFreeOtpPlusFile => 'Para crear una copia de seguridad de la app FreeOTP+, pulse los tres puntos de la esquina superior derecha y seleccione \"Exportar\". Puede elegir entre los formatos JSON y URI. Recomendamos eliminar la copia de seguridad después de importarla, ya que no está cifrada.';
+
@override
String get qrFileDecodeError => 'No fue posible decodificar el código QR de la imagen seleccionada, por favor utilice el escáner de código QR en su lugar.';
@@ -715,4 +739,140 @@ class AppLocalizationsEs extends AppLocalizations {
String requestInfo(Object issuer, Object account) {
return 'Enviado por $issuer para su cuenta: \"$account\"';
}
+
+ @override
+ String errorUnlinkingPushToken(Object label) {
+ return 'Error al desvincular el token push $label';
+ }
+
+ @override
+ String get pleaseSyncManuallyWhenNetworkIsAvailable => 'Por favor, sincronice los tokens push manualmente a través de los ajustes cuando haya una conexión de red disponible.';
+
+ @override
+ String get pushTokens => 'Push Tokens';
+
+ @override
+ String get continueButton => 'Continue';
+
+ @override
+ String get addTokenManually => 'Añadir token manualmente';
+
+ @override
+ String get addFolder => 'Añadir carpeta';
+
+ @override
+ String get searchTokens => 'Buscar tokens';
+
+ @override
+ String get closeSearchTokens => 'Cerrar búsqueda';
+
+ @override
+ String get increaseCounter => 'Incrementar contador';
+
+ @override
+ String get copyOTPToClipboard => 'Copiar OTP al portapapeles';
+
+ @override
+ String get licenses => 'Licencias';
+
+ @override
+ String get optionalMessage => 'Mensaje opcional';
+
+ @override
+ String get confirmation => 'confirmación';
+
+ @override
+ String get askLogSendedDescription => '¿Ha enviado el registro y desea borrarlo ahora?';
+
+ @override
+ String algorithmUnsupported(Object algorithm) {
+ return 'El algoritmo $algorithm no es compatible';
+ }
+
+ @override
+ String get thisAppIsOpenSource => 'Esta aplicación es de código abierto\nVisítanos en GitHub';
+
+ @override
+ String get importExportTokens => 'Importar/Exportar tokens';
+
+ @override
+ String get exportNonPrivacyIDEATokens => 'Exportar tokens no privacyIDEA';
+
+ @override
+ String selectTokensToExport(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Seleccionar tokens para exportar',
+ one: 'Seleccionar token para exportar',
+ zero: '',
+ );
+ return '$_temp0';
+ }
+
+ @override
+ String get noTokensToExport => 'No hay tokens para exportar';
+
+ @override
+ String get exportAllTokens => 'Exportar todos los tokens';
+
+ @override
+ String get export => 'Exportar';
+
+ @override
+ String get exportingTokens => 'Exportando tokens...';
+
+ @override
+ String get exportTokens => 'Exportar tokens';
+
+ @override
+ String get enterPasswordToEncrypt => 'Ingrese una contraseña para cifrar los tokens. Esta contraseña será necesaria para importar los tokens.';
+
+ @override
+ String get exportLockedTokenReason => 'Por favor, autentíquese para exportar tokens bloqueados.';
+
+ @override
+ String get fileSavedToDownloadsFolder => 'Archivo guardado en la carpeta de descargas';
+
+ @override
+ String get errorSavingFile => 'Error al guardar el archivo';
+
+ @override
+ String get toFile => 'A archivo';
+
+ @override
+ String get asQrCode => 'Como código QR';
+
+ @override
+ String get scanThisQrWithNewDevice => 'Escanee este código QR con su nuevo dispositivo para importar el token.';
+
+ @override
+ String get oneMore => 'Uno más';
+
+ @override
+ String get done => 'Hecho';
+
+ @override
+ String get confirmPassword => 'Confirmar contraseña';
+
+ @override
+ String get secretIsRequired => 'Secret is required';
+
+ @override
+ String get tokenDataParseError => 'Token data could not be parsed';
+
+ @override
+ String missingRequiredParameter(Object counter) {
+ return 'Value for parameter [$counter] is required and is missing';
+ }
+
+ @override
+ String invalidValueForParameter(Object value, Object parameter) {
+ return '[$value] is not a valid value for uri parameter [parameter].';
+ }
+
+ @override
+ String unsupported(Object name, Object value) {
+ return 'The $name [$value] is not supported by this version of the app.';
+ }
}
diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart
index 1e69191cf..0b7c478da 100644
--- a/lib/l10n/app_localizations_fr.dart
+++ b/lib/l10n/app_localizations_fr.dart
@@ -142,6 +142,9 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get systemTheme => 'Utiliser le thème de l\'appareil';
+ @override
+ String get someTokensDoNotSupportPolling => 'Certains jetons sont obsolètes et ne supportent pas l\'interrogation due serveur.';
+
@override
String get enablePolling => 'Activer l\'interrogation du serveur.';
@@ -606,6 +609,18 @@ class AppLocalizationsFr extends AppLocalizations {
return 'Le lien saisi n\'est pas un jeton valide de $appName, ou il n\'est pas pris en charge';
}
+ @override
+ String importFailedToken(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Échec de l\'importation des jetons $count.',
+ one: 'Échec de l\'importation d\'un jeton.',
+ zero: 'Pas de jeton Échec de l\'importation.',
+ );
+ return '$_temp0';
+ }
+
@override
String importExistingToken(num count) {
String _temp0 = intl.Intl.pluralLogic(
@@ -660,6 +675,15 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get importHintGoogleQrFile => 'Sélectionnez un fichier image avec le code QR que vous obtenez lorsque vous exportez vos comptes depuis Google Authenticator.\n!! Notez qu\'il n\'est pas sûr d\'enregistrer le code QR sur votre appareil, car les jetons ne sont pas cryptés !!';
+ @override
+ String get importHintAuthenticatorProFile => 'Pour créer une sauvegarde de l\'application Authenticator Pro, accédez aux paramètres et appuyez sur \"Sauvegarde automatique\". Sélectionnez un emplacement de stockage et définissez un mot de passe. Puis appuyez sur \"Sauvegarder maintenant\" pour exporter les tokens.';
+
+ @override
+ String get importHintFreeOtpPlusQrScan => 'Scannez le code QR que vous recevez lorsque vous appuyez sur les trois points dans la tuile du jeton et sélectionnez \"Partager le code QR\".';
+
+ @override
+ String get importHintFreeOtpPlusFile => 'Pour créer une sauvegarde de l\'application FreeOTP+, appuyez sur les trois points dans le coin supérieur droit et sélectionnez \"Exporter\". Vous pouvez choisir entre les formats JSON et URI. Nous recommandons de supprimer la sauvegarde après l\'avoir importée, car elle n\'est pas cryptée.';
+
@override
String get qrFileDecodeError => 'Il n\'a pas été possible de décoder le code QR à partir de l\'image sélectionnée, veuillez utiliser le scanner de code QR à la place';
@@ -715,4 +739,140 @@ class AppLocalizationsFr extends AppLocalizations {
String requestInfo(Object issuer, Object account) {
return 'Envoyé par $issuer pour votre compte : \"$account\"';
}
+
+ @override
+ String errorUnlinkingPushToken(Object label) {
+ return 'Echec du découplage du push token $label';
+ }
+
+ @override
+ String get pleaseSyncManuallyWhenNetworkIsAvailable => 'Veuillez synchroniser manuellement les jetons Push via les paramètres lorsqu\'une connexion réseau est disponible';
+
+ @override
+ String get pushTokens => 'Push Tokens';
+
+ @override
+ String get continueButton => 'Continue';
+
+ @override
+ String get addTokenManually => 'Add token manually';
+
+ @override
+ String get addFolder => 'Ajouter un dossier';
+
+ @override
+ String get searchTokens => 'Jetons de recherche';
+
+ @override
+ String get closeSearchTokens => 'Fermer la recherche';
+
+ @override
+ String get increaseCounter => 'Augmenter le compteur';
+
+ @override
+ String get copyOTPToClipboard => 'Copier l\'OTP dans le presse-papiers';
+
+ @override
+ String get licenses => 'Licences';
+
+ @override
+ String get optionalMessage => 'Message optionnel';
+
+ @override
+ String get confirmation => 'Confirmation';
+
+ @override
+ String get askLogSendedDescription => 'Avez-vous envoyé le journal et voulez-vous l\'effacer maintenant ?';
+
+ @override
+ String algorithmUnsupported(Object algorithm) {
+ return 'L\'algorithme $algorithm n\'est pas pris en charge';
+ }
+
+ @override
+ String get thisAppIsOpenSource => 'Cette application est open source\nRendez-nous visite sur GitHub';
+
+ @override
+ String get importExportTokens => 'Importer/Exporter les jetons';
+
+ @override
+ String get exportNonPrivacyIDEATokens => 'Exporter les jetons non privacyIDEA';
+
+ @override
+ String selectTokensToExport(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Sélectionner les jetons à exporter',
+ one: 'Sélectionner le jeton à exporter',
+ zero: '',
+ );
+ return '$_temp0';
+ }
+
+ @override
+ String get noTokensToExport => 'Aucun jeton à exporter';
+
+ @override
+ String get exportAllTokens => 'Exporter tous les jetons';
+
+ @override
+ String get export => 'Exporter';
+
+ @override
+ String get exportingTokens => 'Exportation des jetons en cours...';
+
+ @override
+ String get exportTokens => 'Exporter les jetons';
+
+ @override
+ String get enterPasswordToEncrypt => 'Entrez un mot de passe pour chiffrer les jetons. Ce mot de passe sera requis pour importer les jetons.';
+
+ @override
+ String get exportLockedTokenReason => 'Veuillez vous authentifier pour exporter les jetons verrouillés.';
+
+ @override
+ String get fileSavedToDownloadsFolder => 'Fichier enregistré dans le dossier Téléchargements';
+
+ @override
+ String get errorSavingFile => 'Erreur lors de l\'enregistrement du fichier';
+
+ @override
+ String get toFile => 'Vers fichier';
+
+ @override
+ String get asQrCode => 'Sous forme de code QR';
+
+ @override
+ String get scanThisQrWithNewDevice => 'Scannez ce code QR avec votre nouvel appareil pour importer le jeton.';
+
+ @override
+ String get oneMore => 'Encore un';
+
+ @override
+ String get done => 'Terminé';
+
+ @override
+ String get confirmPassword => 'Confirmer le mot de passe';
+
+ @override
+ String get secretIsRequired => 'Secret is required';
+
+ @override
+ String get tokenDataParseError => 'Token data could not be parsed';
+
+ @override
+ String missingRequiredParameter(Object counter) {
+ return 'Value for parameter [$counter] is required and is missing';
+ }
+
+ @override
+ String invalidValueForParameter(Object value, Object parameter) {
+ return '[$value] is not a valid value for uri parameter [parameter].';
+ }
+
+ @override
+ String unsupported(Object name, Object value) {
+ return 'The $name [$value] is not supported by this version of the app.';
+ }
}
diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart
index b2bd2d0c0..372e68eb5 100644
--- a/lib/l10n/app_localizations_nl.dart
+++ b/lib/l10n/app_localizations_nl.dart
@@ -142,6 +142,9 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get systemTheme => 'Gebruik thema van het apparaat';
+ @override
+ String get someTokensDoNotSupportPolling => 'Sommige tokens zijn verouderd en ondersteunen geen actief zoeken';
+
@override
String get enablePolling => 'Zoeken aanzetten';
@@ -606,6 +609,18 @@ class AppLocalizationsNl extends AppLocalizations {
return 'De ingevoerde link is geen geldig token van $appName, of wordt niet ondersteund.';
}
+ @override
+ String importFailedToken(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Kan $count tokens niet importeren.',
+ one: 'Kan geen token importeren.',
+ zero: 'Geen token Niet geïmporteerd.',
+ );
+ return '$_temp0';
+ }
+
@override
String importExistingToken(num count) {
String _temp0 = intl.Intl.pluralLogic(
@@ -660,6 +675,15 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get importHintGoogleQrFile => 'Selecteer een afbeeldingsbestand met de QR-code die u ontvangt wanneer u uw accounts exporteert vanuit Google Authenticator.\n!! Let op: het is niet veilig om de QR-code op je apparaat op te slaan, omdat de tokens niet versleuteld zijn !!';
+ @override
+ String get importHintAuthenticatorProFile => 'Om een back-up te maken van de Authenticator Pro app, navigeer je naar de instellingen en tik je op \"Auto back-up\". Selecteer een opslaglocatie en stel een wachtwoord in. Druk vervolgens op \"Nu back-uppen\" om de tokens te exporteren.';
+
+ @override
+ String get importHintFreeOtpPlusQrScan => 'Scan de QR-code die u ontvangt wanneer u op de drie stippen in de tegel van de token drukt en selecteer \"QR-code delen\".';
+
+ @override
+ String get importHintFreeOtpPlusFile => 'Om een back-up van de FreeOTP+ app te maken, tikt u op de drie puntjes in de rechterbovenhoek en selecteert u \"Exporteren\". U kunt kiezen tussen JSON en URI formaat. We raden u aan de back-up te verwijderen na het importeren, omdat deze niet versleuteld is.';
+
@override
String get qrFileDecodeError => 'Het was niet mogelijk om de QR code te decoderen van de geselecteerde afbeelding, gebruik in plaats daarvan de QR code scanner.';
@@ -715,4 +739,140 @@ class AppLocalizationsNl extends AppLocalizations {
String requestInfo(Object issuer, Object account) {
return 'Verzonden door $issuer voor uw account: \"$account\"';
}
+
+ @override
+ String errorUnlinkingPushToken(Object label) {
+ return 'Het is niet gelukt om het push token $label te ontkoppelen.';
+ }
+
+ @override
+ String get pleaseSyncManuallyWhenNetworkIsAvailable => 'Synchroniseer de push tokens handmatig via de instellingen als er een netwerkverbinding beschikbaar is.';
+
+ @override
+ String get pushTokens => 'Push Tokens';
+
+ @override
+ String get continueButton => 'Ga verder';
+
+ @override
+ String get addTokenManually => 'Voeg token handmatig toe';
+
+ @override
+ String get addFolder => 'Map toevoegen';
+
+ @override
+ String get searchTokens => 'Zoek tokens';
+
+ @override
+ String get closeSearchTokens => 'Zoekopdracht sluiten';
+
+ @override
+ String get increaseCounter => 'Verhoog teller';
+
+ @override
+ String get copyOTPToClipboard => 'Kopieer OTP naar klembord';
+
+ @override
+ String get licenses => 'Licenties';
+
+ @override
+ String get optionalMessage => 'Optioneel bericht';
+
+ @override
+ String get confirmation => 'Bevestiging';
+
+ @override
+ String get askLogSendedDescription => 'Heb je het logboek verzonden en wil je het nu wissen?';
+
+ @override
+ String algorithmUnsupported(Object algorithm) {
+ return 'Het algoritme $algorithm wordt niet ondersteund';
+ }
+
+ @override
+ String get thisAppIsOpenSource => 'Deze app is open source\nBezoek ons op GitHub';
+
+ @override
+ String get importExportTokens => 'Tokens importeren/exporteren';
+
+ @override
+ String get exportNonPrivacyIDEATokens => 'Niet-privacyIDEA tokens exporteren';
+
+ @override
+ String selectTokensToExport(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Selecteer tokens om te exporteren',
+ one: 'Selecteer token om te exporteren',
+ zero: '',
+ );
+ return '$_temp0';
+ }
+
+ @override
+ String get noTokensToExport => 'Geen tokens om te exporteren';
+
+ @override
+ String get exportAllTokens => 'Alle tokens exporteren';
+
+ @override
+ String get export => 'Exporteren';
+
+ @override
+ String get exportingTokens => 'Tokens exporteren...';
+
+ @override
+ String get exportTokens => 'Tokens exporteren';
+
+ @override
+ String get enterPasswordToEncrypt => 'Voer een wachtwoord in om de tokens te versleutelen. Dit wachtwoord is vereist om de tokens te importeren.';
+
+ @override
+ String get exportLockedTokenReason => 'Authenticeer om vergrendelde tokens te exporteren.';
+
+ @override
+ String get fileSavedToDownloadsFolder => 'Bestand opgeslagen in de map Downloads';
+
+ @override
+ String get errorSavingFile => 'Fout bij het opslaan van het bestand';
+
+ @override
+ String get toFile => 'Naar bestand';
+
+ @override
+ String get asQrCode => 'Als QR-code';
+
+ @override
+ String get scanThisQrWithNewDevice => 'Scan deze QR-code met uw nieuwe apparaat om de token te importeren.';
+
+ @override
+ String get oneMore => 'Nog een';
+
+ @override
+ String get done => 'Klaar';
+
+ @override
+ String get confirmPassword => 'Wachtwoord bevestigen';
+
+ @override
+ String get secretIsRequired => 'Secret is required';
+
+ @override
+ String get tokenDataParseError => 'Token data could not be parsed';
+
+ @override
+ String missingRequiredParameter(Object counter) {
+ return 'Value for parameter [$counter] is required and is missing';
+ }
+
+ @override
+ String invalidValueForParameter(Object value, Object parameter) {
+ return '[$value] is not a valid value for uri parameter [parameter].';
+ }
+
+ @override
+ String unsupported(Object name, Object value) {
+ return 'The $name [$value] is not supported by this version of the app.';
+ }
}
diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart
index 1ec61e612..e9d999ede 100644
--- a/lib/l10n/app_localizations_pl.dart
+++ b/lib/l10n/app_localizations_pl.dart
@@ -142,6 +142,9 @@ class AppLocalizationsPl extends AppLocalizations {
@override
String get systemTheme => 'Motyw systemu';
+ @override
+ String get someTokensDoNotSupportPolling => 'Część tokenów jest przestarzała i nie wspiera aktywnego zapytania dla autentykacji przez wiadomość push.';
+
@override
String get enablePolling => 'Włącz autentykację przez wiadomość push.';
@@ -606,6 +609,18 @@ class AppLocalizationsPl extends AppLocalizations {
return 'Wprowadzony link nie jest prawidłowym tokenem $appName lub nie jest obsługiwany.';
}
+ @override
+ String importFailedToken(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Nie udało się zaimportować $count tokenów.',
+ one: 'Nie udało się zaimportować tokena.',
+ zero: 'Nie udało się zaimportować tokenu.',
+ );
+ return '$_temp0';
+ }
+
@override
String importExistingToken(num count) {
String _temp0 = intl.Intl.pluralLogic(
@@ -660,6 +675,15 @@ class AppLocalizationsPl extends AppLocalizations {
@override
String get importHintGoogleQrFile => 'Wybierz plik obrazu z kodem QR otrzymanym podczas eksportowania kont z Google Authenticator.\n!! Należy pamiętać, że zapisywanie kodu QR na urządzeniu nie jest bezpieczne, ponieważ tokeny nie są szyfrowane !!';
+ @override
+ String get importHintAuthenticatorProFile => 'Aby utworzyć kopię zapasową aplikacji Authenticator Pro, przejdź do ustawień i dotknij \"Automatyczna kopia zapasowa\". Wybierz lokalizację przechowywania i ustaw hasło. Następnie naciśnij \"Utwórz teraz kopię zapasową\", aby wyeksportować tokeny.';
+
+ @override
+ String get importHintFreeOtpPlusQrScan => 'Zeskanuj kod QR otrzymany po naciśnięciu trzech kropek na kafelku tokena i wybierz \"Udostępnij kod QR\".';
+
+ @override
+ String get importHintFreeOtpPlusFile => 'Aby utworzyć kopię zapasową aplikacji FreeOTP+, dotknij trzech kropek w prawym górnym rogu i wybierz \"Eksportuj\". Można wybrać format JSON lub URI. Zalecamy usunięcie kopii zapasowej po jej zaimportowaniu, ponieważ nie jest ona szyfrowana.';
+
@override
String get qrFileDecodeError => 'Nie można było zdekodować kodu QR z wybranego obrazu, zamiast tego użyj skanera kodów QR.';
@@ -715,4 +739,140 @@ class AppLocalizationsPl extends AppLocalizations {
String requestInfo(Object issuer, Object account) {
return 'Wysłane przez $issuer dla twojego konta: \"$account\"';
}
+
+ @override
+ String errorUnlinkingPushToken(Object label) {
+ return 'Nie udało się odłączyć tokenu push $label.';
+ }
+
+ @override
+ String get pleaseSyncManuallyWhenNetworkIsAvailable => 'Zsynchronizuj tokeny push ręcznie za pomocą ustawień, gdy dostępne jest połączenie sieciowe';
+
+ @override
+ String get pushTokens => 'Tokeny push';
+
+ @override
+ String get continueButton => 'Kontynuuj';
+
+ @override
+ String get addTokenManually => 'Dodaj token ręcznie';
+
+ @override
+ String get addFolder => 'Dodaj folder';
+
+ @override
+ String get searchTokens => 'Wyszukiwanie tokenów';
+
+ @override
+ String get closeSearchTokens => 'Zamknij wyszukiwanie';
+
+ @override
+ String get increaseCounter => 'Zwiększ licznik';
+
+ @override
+ String get copyOTPToClipboard => 'Kopiowanie OTP do schowka';
+
+ @override
+ String get licenses => 'Licencja';
+
+ @override
+ String get optionalMessage => 'Opcjonalna wiadomość';
+
+ @override
+ String get confirmation => 'potwierdzenie';
+
+ @override
+ String get askLogSendedDescription => 'Czy wysłałeś dziennik i czy chcesz go teraz wyczyścić?';
+
+ @override
+ String algorithmUnsupported(Object algorithm) {
+ return 'Algorytm $algorithm nie jest obsługiwany';
+ }
+
+ @override
+ String get thisAppIsOpenSource => 'Ta aplikacja jest open source\nOdwiedź nas na GitHub';
+
+ @override
+ String get importExportTokens => 'Importuj/Eksportuj tokeny';
+
+ @override
+ String get exportNonPrivacyIDEATokens => 'Eksportuj tokeny niebędące privacyIDEA';
+
+ @override
+ String selectTokensToExport(num count) {
+ String _temp0 = intl.Intl.pluralLogic(
+ count,
+ locale: localeName,
+ other: 'Wybierz tokeny do wyeksportowania',
+ one: 'Wybierz token do wyeksportowania',
+ zero: '',
+ );
+ return '$_temp0';
+ }
+
+ @override
+ String get noTokensToExport => 'Brak tokenów do wyeksportowania';
+
+ @override
+ String get exportAllTokens => 'Eksportuj wszystkie tokeny';
+
+ @override
+ String get export => 'Eksportuj';
+
+ @override
+ String get exportingTokens => 'Eksportowanie tokenów...';
+
+ @override
+ String get exportTokens => 'Eksportuj tokeny';
+
+ @override
+ String get enterPasswordToEncrypt => 'Wprowadź hasło, aby zaszyfrować tokeny. To hasło będzie wymagane do importu tokenów.';
+
+ @override
+ String get exportLockedTokenReason => 'Proszę uwierzytelnić się, aby wyeksportować zablokowane tokeny.';
+
+ @override
+ String get fileSavedToDownloadsFolder => 'Plik zapisano w folderze Pobrane';
+
+ @override
+ String get errorSavingFile => 'Błąd podczas zapisywania pliku';
+
+ @override
+ String get toFile => 'Do pliku';
+
+ @override
+ String get asQrCode => 'Jako kod QR';
+
+ @override
+ String get scanThisQrWithNewDevice => 'Zeskanuj ten kod QR za pomocą nowego urządzenia, aby zaimportować token.';
+
+ @override
+ String get oneMore => 'Jeszcze jeden';
+
+ @override
+ String get done => 'Gotowe';
+
+ @override
+ String get confirmPassword => 'Potwierdź hasło';
+
+ @override
+ String get secretIsRequired => 'Secret is required';
+
+ @override
+ String get tokenDataParseError => 'Token data could not be parsed';
+
+ @override
+ String missingRequiredParameter(Object counter) {
+ return 'Value for parameter [$counter] is required and is missing';
+ }
+
+ @override
+ String invalidValueForParameter(Object value, Object parameter) {
+ return '[$value] is not a valid value for uri parameter [parameter].';
+ }
+
+ @override
+ String unsupported(Object name, Object value) {
+ return 'The $name [$value] is not supported by this version of the app.';
+ }
}
diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb
index edc35027b..f335e4b29 100644
--- a/lib/l10n/app_nl.arb
+++ b/lib/l10n/app_nl.arb
@@ -157,6 +157,12 @@
"@systemTheme": {
"description": "The systems theme."
},
+ "someTokensDoNotSupportPolling": "Sommige tokens zijn verouderd en ondersteunen geen actief zoeken",
+ "@someTokensDoNotSupportPolling": {
+ "description": "Tells the user, that the following tokens do not support polling.",
+ "type": "text",
+ "placeholders": {}
+ },
"enablePolling": "Zoeken aanzetten",
"@enablePolling": {
"description": "Name of the setting switch that enables polling."
@@ -533,6 +539,7 @@
"invalidQrScan": "De gescande QR code is geen geldige backup van {appName}.",
"invalidQrFile": "Het geselecteerde bestand bevat geen geldige QR code van {appName}.",
"invalidLink": "De ingevoerde link is geen geldig token van {appName}, of wordt niet ondersteund.",
+ "importFailedToken": "{count, plural, zero{Geen token Niet geïmporteerd.} one{Kan geen token importeren.} other{Kan {count} tokens niet importeren.}}",
"importExistingToken": "{count, plural, zero{Er is geen token gevonden dat al in de toepassing aanwezig is.} one{Er is een token gevonden dat al bestaat in de applicatie.} other{{count} tokens gevonden die al in de applicatie staan.}}",
"importConflictToken": "{count, plural, zero{Er is geen conflict met tokens die al bestaan.} one{Er is een conflict met tokens die al bestaan.Selecteer welke u wilt behouden.} other{Er is een conflict met tokens die al bestaan.Selecteer welke u wilt behouden.}}",
"importNewToken": "{count, plural, zero{Er is geen nieuw token gevonden.} one{Er is een nieuw token gevonden dat zal worden geïmporteerd.} other{Er is een nieuw token {count} gevonden dat zal worden geïmporteerd.}}",
@@ -542,6 +549,9 @@
"importHintAegisLink": "Voer de link in die u ontvangt wanneer u vermeldingen van Aegis overdraagt.",
"importHintGoogleQrScan": "Scan de QR-code die u ontvangt wanneer u uw accounts exporteert vanuit Google Authenticator.",
"importHintGoogleQrFile": "Selecteer een afbeeldingsbestand met de QR-code die u ontvangt wanneer u uw accounts exporteert vanuit Google Authenticator.\n!! Let op: het is niet veilig om de QR-code op je apparaat op te slaan, omdat de tokens niet versleuteld zijn !!",
+ "importHintAuthenticatorProFile": "Om een back-up te maken van de Authenticator Pro app, navigeer je naar de instellingen en tik je op \"Auto back-up\". Selecteer een opslaglocatie en stel een wachtwoord in. Druk vervolgens op \"Nu back-uppen\" om de tokens te exporteren.",
+ "importHintFreeOtpPlusQrScan": "Scan de QR-code die u ontvangt wanneer u op de drie stippen in de tegel van de token drukt en selecteer \"QR-code delen\".",
+ "importHintFreeOtpPlusFile": "Om een back-up van de FreeOTP+ app te maken, tikt u op de drie puntjes in de rechterbovenhoek en selecteert u \"Exporteren\". U kunt kiezen tussen JSON en URI formaat. We raden u aan de back-up te verwijderen na het importeren, omdat deze niet versleuteld is.",
"qrFileDecodeError": "Het was niet mogelijk om de QR code te decoderen van de geselecteerde afbeelding, gebruik in plaats daarvan de QR code scanner.",
"tokenLink": "tokenlink",
"feedback": "Feedback",
@@ -572,5 +582,55 @@
"example": "GitHub"
}
}
- }
+ },
+ "errorUnlinkingPushToken": "Het is niet gelukt om het push token {label} te ontkoppelen.",
+ "@errorUnlinkingPushToken": {
+ "description": "Error message when unlinking a push token failed.",
+ "placeholders": {
+ "label": {
+ "example": "PUSH1234A"
+ }
+ }
+ },
+ "pleaseSyncManuallyWhenNetworkIsAvailable": "Synchroniseer de push tokens handmatig via de instellingen als er een netwerkverbinding beschikbaar is.",
+ "pushTokens": "Push Tokens",
+ "continueButton": "Ga verder",
+ "addTokenManually": "Voeg token handmatig toe",
+ "addFolder": "Map toevoegen",
+ "searchTokens": "Zoek tokens",
+ "closeSearchTokens": "Zoekopdracht sluiten",
+ "increaseCounter": "Verhoog teller",
+ "copyOTPToClipboard": "Kopieer OTP naar klembord",
+ "licenses": "Licenties",
+ "optionalMessage": "Optioneel bericht",
+ "confirmation": "Bevestiging",
+ "askLogSendedDescription": "Heb je het logboek verzonden en wil je het nu wissen?",
+ "algorithmUnsupported": "Het algoritme {algorithm} wordt niet ondersteund",
+ "@algorithmUnsupported": {
+ "placeholders": {
+ "algorithm": {
+ "example": "MD5"
+ }
+ }
+ },
+ "thisAppIsOpenSource": "Deze app is open source\nBezoek ons op GitHub",
+ "invalidArgument": "{argument} is geen geldige waarde voor {type}",
+ "importExportTokens": "Tokens importeren/exporteren",
+ "exportNonPrivacyIDEATokens": "Niet-privacyIDEA tokens exporteren",
+ "selectTokensToExport": "{count, plural, zero{} one{Selecteer token om te exporteren} other{Selecteer tokens om te exporteren}}",
+ "noTokensToExport": "Geen tokens om te exporteren",
+ "exportAllTokens": "Alle tokens exporteren",
+ "export": "Exporteren",
+ "exportingTokens": "Tokens exporteren...",
+ "exportTokens": "Tokens exporteren",
+ "enterPasswordToEncrypt": "Voer een wachtwoord in om de tokens te versleutelen. Dit wachtwoord is vereist om de tokens te importeren.",
+ "exportLockedTokenReason": "Authenticeer om vergrendelde tokens te exporteren.",
+ "fileSavedToDownloadsFolder": "Bestand opgeslagen in de map Downloads",
+ "errorSavingFile": "Fout bij het opslaan van het bestand",
+ "toFile": "Naar bestand",
+ "asQrCode": "Als QR-code",
+ "scanThisQrWithNewDevice": "Scan deze QR-code met uw nieuwe apparaat om de token te importeren.",
+ "oneMore": "Nog een",
+ "done": "Klaar",
+ "confirmPassword": "Wachtwoord bevestigen"
}
\ No newline at end of file
diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb
index 8d5e663e5..04681aa25 100644
--- a/lib/l10n/app_pl.arb
+++ b/lib/l10n/app_pl.arb
@@ -159,6 +159,12 @@
"@systemTheme": {
"description": "The systems theme."
},
+ "someTokensDoNotSupportPolling": "Część tokenów jest przestarzała i nie wspiera aktywnego zapytania dla autentykacji przez wiadomość push.",
+ "@someTokensDoNotSupportPolling": {
+ "description": "Tells the user, that the following tokens do not support polling.",
+ "type": "text",
+ "placeholders": {}
+ },
"enablePolling": "Włącz autentykację przez wiadomość push.",
"@enablePolling": {
"description": "Name of the setting switch that enables polling."
@@ -530,6 +536,7 @@
"invalidQrScan": "Zeskanowany kod QR nie jest prawidłową kopią zapasową {appName}.",
"invalidQrFile": "Wybrany plik nie zawiera prawidłowego kodu QR z {appName}.",
"invalidLink": "Wprowadzony link nie jest prawidłowym tokenem {appName} lub nie jest obsługiwany.",
+ "importFailedToken": "{count, plural, zero{Nie udało się zaimportować tokenu.} one{Nie udało się zaimportować tokena.} other{Nie udało się zaimportować {count} tokenów.}}",
"importExistingToken": "{count, plural, zero{Nie znaleziono tokena, który już znajduje się w aplikacji.} one{Znaleziono token, który już istnieje w aplikacji.} other{Znaleziono {count} tokenów, które już znajdują się w aplikacji.}}",
"importConflictToken": "{count, plural, zero{Nie ma konfliktu z tokenami, które już istnieją.} one{Istnieje konflikt z tokenami, które już istnieją.} other{Istnieje konflikt z tokenami, które już istnieją.}}",
"importNewToken": "{count, plural, zero{Nie znaleziono nowego tokena.} one{Znaleziono nowy token, który zostanie zaimportowany.} other{Znaleziono nowy token {count}, który zostanie zaimportowany.}}",
@@ -539,6 +546,9 @@
"importHintAegisLink": "Wprowadź link otrzymany podczas przesyłania wpisów z Aegis.",
"importHintGoogleQrScan": "Zeskanuj kod QR otrzymany podczas eksportowania kont z Google Authenticator",
"importHintGoogleQrFile": "Wybierz plik obrazu z kodem QR otrzymanym podczas eksportowania kont z Google Authenticator.\n!! Należy pamiętać, że zapisywanie kodu QR na urządzeniu nie jest bezpieczne, ponieważ tokeny nie są szyfrowane !!",
+ "importHintAuthenticatorProFile": "Aby utworzyć kopię zapasową aplikacji Authenticator Pro, przejdź do ustawień i dotknij \"Automatyczna kopia zapasowa\". Wybierz lokalizację przechowywania i ustaw hasło. Następnie naciśnij \"Utwórz teraz kopię zapasową\", aby wyeksportować tokeny.",
+ "importHintFreeOtpPlusQrScan": "Zeskanuj kod QR otrzymany po naciśnięciu trzech kropek na kafelku tokena i wybierz \"Udostępnij kod QR\".",
+ "importHintFreeOtpPlusFile": "Aby utworzyć kopię zapasową aplikacji FreeOTP+, dotknij trzech kropek w prawym górnym rogu i wybierz \"Eksportuj\". Można wybrać format JSON lub URI. Zalecamy usunięcie kopii zapasowej po jej zaimportowaniu, ponieważ nie jest ona szyfrowana.",
"qrFileDecodeError": "Nie można było zdekodować kodu QR z wybranego obrazu, zamiast tego użyj skanera kodów QR.",
"tokenLink": "TokenLink",
"feedback": "Informacje zwrotne",
@@ -569,5 +579,55 @@
"example": "GitHub"
}
}
- }
+ },
+ "errorUnlinkingPushToken": "Nie udało się odłączyć tokenu push {label}.",
+ "@errorUnlinkingPushToken": {
+ "description": "Error message when unlinking a push token failed.",
+ "placeholders": {
+ "label": {
+ "example": "PUSH1234A"
+ }
+ }
+ },
+ "pleaseSyncManuallyWhenNetworkIsAvailable": "Zsynchronizuj tokeny push ręcznie za pomocą ustawień, gdy dostępne jest połączenie sieciowe",
+ "pushTokens": "Tokeny push",
+ "continueButton": "Kontynuuj",
+ "addTokenManually": "Dodaj token ręcznie",
+ "addFolder": "Dodaj folder",
+ "searchTokens": "Wyszukiwanie tokenów",
+ "closeSearchTokens": "Zamknij wyszukiwanie",
+ "increaseCounter": "Zwiększ licznik",
+ "copyOTPToClipboard": "Kopiowanie OTP do schowka",
+ "licenses": "Licencja",
+ "optionalMessage": "Opcjonalna wiadomość",
+ "confirmation": "potwierdzenie",
+ "askLogSendedDescription": "Czy wysłałeś dziennik i czy chcesz go teraz wyczyścić?",
+ "algorithmUnsupported": "Algorytm {algorithm} nie jest obsługiwany",
+ "@algorithmUnsupported": {
+ "placeholders": {
+ "algorithm": {
+ "example": "MD5"
+ }
+ }
+ },
+ "thisAppIsOpenSource": "Ta aplikacja jest open source\nOdwiedź nas na GitHub",
+ "invalidArgument": "{argument} nie jest prawidłową wartością dla {type}",
+ "importExportTokens": "Importuj/Eksportuj tokeny",
+ "exportNonPrivacyIDEATokens": "Eksportuj tokeny niebędące privacyIDEA",
+ "selectTokensToExport": "{count, plural, zero{} one{Wybierz token do wyeksportowania} other{Wybierz tokeny do wyeksportowania}}",
+ "noTokensToExport": "Brak tokenów do wyeksportowania",
+ "exportAllTokens": "Eksportuj wszystkie tokeny",
+ "export": "Eksportuj",
+ "exportingTokens": "Eksportowanie tokenów...",
+ "exportTokens": "Eksportuj tokeny",
+ "enterPasswordToEncrypt": "Wprowadź hasło, aby zaszyfrować tokeny. To hasło będzie wymagane do importu tokenów.",
+ "exportLockedTokenReason": "Proszę uwierzytelnić się, aby wyeksportować zablokowane tokeny.",
+ "fileSavedToDownloadsFolder": "Plik zapisano w folderze Pobrane",
+ "errorSavingFile": "Błąd podczas zapisywania pliku",
+ "toFile": "Do pliku",
+ "asQrCode": "Jako kod QR",
+ "scanThisQrWithNewDevice": "Zeskanuj ten kod QR za pomocą nowego urządzenia, aby zaimportować token.",
+ "oneMore": "Jeszcze jeden",
+ "done": "Gotowe",
+ "confirmPassword": "Potwierdź hasło"
}
\ No newline at end of file
diff --git a/lib/mains/main_customizer.dart b/lib/mains/main_customizer.dart
index 27d9e59cc..f11979325 100644
--- a/lib/mains/main_customizer.dart
+++ b/lib/mains/main_customizer.dart
@@ -19,8 +19,6 @@
limitations under the License.
*/
-import 'dart:developer';
-
import 'package:easy_dynamic_theme/easy_dynamic_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -31,7 +29,6 @@ import 'package:privacyidea_authenticator/utils/riverpod_providers.dart';
import 'package:privacyidea_authenticator/views/add_token_manually_view/add_token_manually_view.dart';
import 'package:privacyidea_authenticator/views/license_view/license_view.dart';
import 'package:privacyidea_authenticator/views/main_view/main_view.dart';
-import 'package:privacyidea_authenticator/views/onboarding_view/onboarding_view.dart';
import 'package:privacyidea_authenticator/views/qr_scanner_view/qr_scanner_view.dart';
import 'package:privacyidea_authenticator/views/settings_view/settings_view.dart';
import 'package:privacyidea_authenticator/views/splash_screen/splash_screen.dart';
@@ -60,8 +57,6 @@ class CustomizationAuthenticator extends ConsumerWidget {
final state = ref.watch(settingsProvider);
final locale = state.currentLocale;
final applicationCustomizer = ref.watch(applicationCustomizerProvider);
- log('applicationCustomizer primaryColor: ${applicationCustomizer.lightTheme.primaryColor}');
- log('applicationCustomizer primaryColor gen: ${applicationCustomizer.generateLightTheme().primaryColor}');
return LayoutBuilder(
builder: (context, constraints) {
WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -83,9 +78,6 @@ class CustomizationAuthenticator extends ConsumerWidget {
SplashScreen.routeName: (context) => SplashScreen(
customization: applicationCustomizer,
),
- OnboardingView.routeName: (context) => OnboardingView(
- appName: applicationCustomizer.appName,
- ),
MainView.routeName: (context) => MainView(
appIcon: applicationCustomizer.appIcon,
appName: applicationCustomizer.appName,
diff --git a/lib/mains/main_netknights.dart b/lib/mains/main_netknights.dart
index 2df0d3060..82661d394 100644
--- a/lib/mains/main_netknights.dart
+++ b/lib/mains/main_netknights.dart
@@ -18,11 +18,12 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
+
import 'package:easy_dynamic_theme/easy_dynamic_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:privacyidea_authenticator/l10n/app_localizations.dart';
-import 'package:privacyidea_authenticator/utils/app_customizer.dart';
+import 'package:privacyidea_authenticator/utils/customization/application_customization.dart';
import 'package:privacyidea_authenticator/utils/globals.dart';
import 'package:privacyidea_authenticator/utils/logger.dart';
import 'package:privacyidea_authenticator/utils/riverpod_providers.dart';
@@ -30,7 +31,6 @@ import 'package:privacyidea_authenticator/views/add_token_manually_view/add_toke
import 'package:privacyidea_authenticator/views/import_tokens_view/import_tokens_view.dart';
import 'package:privacyidea_authenticator/views/license_view/license_view.dart';
import 'package:privacyidea_authenticator/views/main_view/main_view.dart';
-import 'package:privacyidea_authenticator/views/onboarding_view/onboarding_view.dart';
import 'package:privacyidea_authenticator/views/push_token_view/push_tokens_view.dart';
import 'package:privacyidea_authenticator/views/qr_scanner_view/qr_scanner_view.dart';
import 'package:privacyidea_authenticator/views/settings_view/settings_view.dart';
@@ -48,17 +48,20 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized();
await HomeWidgetUtils().registerInteractivityCallback(homeWidgetBackgroundCallback);
await HomeWidgetUtils().setAppGroupId(appGroupId);
- runApp(AppWrapper(child: PrivacyIDEAAuthenticator(customization: ApplicationCustomization.defaultCustomization)));
+ runApp(AppWrapper(child: PrivacyIDEAAuthenticator(ApplicationCustomization.defaultCustomization)));
});
}
class PrivacyIDEAAuthenticator extends ConsumerWidget {
static ApplicationCustomization? currentCustomization;
final ApplicationCustomization _customization;
- PrivacyIDEAAuthenticator({required ApplicationCustomization customization, super.key}) : _customization = customization {
- // ignore: prefer_initializing_formals
+
+ factory PrivacyIDEAAuthenticator(ApplicationCustomization customization, {Key? key}) {
PrivacyIDEAAuthenticator.currentCustomization = customization;
+ return PrivacyIDEAAuthenticator._(customization: customization, key: key);
}
+ const PrivacyIDEAAuthenticator._({required ApplicationCustomization customization, super.key}) : _customization = customization;
+
@override
Widget build(BuildContext context, WidgetRef ref) {
globalRef = ref;
@@ -97,14 +100,9 @@ class PrivacyIDEAAuthenticator extends ConsumerWidget {
appName: _customization.appName,
disablePatchNotes: _customization.disabledFeatures.contains(AppFeature.patchNotes),
),
- OnboardingView.routeName: (context) => OnboardingView(
- appName: _customization.appName,
- ),
PushTokensView.routeName: (context) => const PushTokensView(),
SettingsView.routeName: (context) => const SettingsView(),
- SplashScreen.routeName: (context) => SplashScreen(
- customization: _customization,
- ),
+ SplashScreen.routeName: (context) => SplashScreen(customization: _customization),
QRScannerView.routeName: (context) => const QRScannerView(),
},
);
diff --git a/lib/model/encryption/aes_encrypted.dart b/lib/model/encryption/aes_encrypted.dart
index 87bf6c6d0..4e8ca823c 100644
--- a/lib/model/encryption/aes_encrypted.dart
+++ b/lib/model/encryption/aes_encrypted.dart
@@ -1,50 +1,280 @@
import 'dart:convert';
+import 'dart:math';
import 'dart:typed_data';
import 'package:cryptography/cryptography.dart';
-import 'package:encrypt/encrypt.dart';
+import 'package:cryptography/dart.dart';
+import 'package:flutter/foundation.dart';
-class AESEncrypted {
- final Uint8List data;
+class AesEncrypted {
+ // [KdfAlgorithm/MacAlgorithm/Iterations/Bits]
+ static const Map defaultKdfSettings = {
+ 'algorithm': 'PBKDF2',
+ 'macAlgorithm': 'HmacSHA256',
+ 'iterations': 100000,
+ 'bits': 256,
+ };
+ static final defaultMacAlgorithm = Hmac.sha256();
+ static const defaultIterations = 100000;
+ static const defaultBits = 256;
+ // Key derivation
+ final KdfAlgorithm kdf;
final Uint8List salt;
+
+ // Encryption
+ final Uint8List data;
final Uint8List iv;
- final String ivBase64;
- final String padding;
- final Hmac macAlgorithm;
- final int iterations;
- // final int keyBitLengh;
- final AESMode aesMode;
-
- String? decryptedString;
-
- AESEncrypted(
- {required this.data, required this.salt, required this.iv, String? padding, Hmac? macAlgorithm, int? iterations, int? keyBitLengh, AESMode? aesMode})
- : //dataBytes = base64Decode(data),
- // saltBytes = base64Decode(salt),
- // ivBytes = base64Decode(iv),
- padding = padding ?? 'PKCS7',
- ivBase64 = base64Encode(iv),
- macAlgorithm = macAlgorithm ?? Hmac.sha256(),
- iterations = iterations ?? 10000,
- // keyBitLengh = keyBitLengh ?? 128,//
- aesMode = aesMode ?? AESMode.gcm;
-
- Future decrypt(String password) async {
- final keyGenerator = Pbkdf2(macAlgorithm: macAlgorithm, iterations: iterations, bits: salt.length * 8);
-
- final SecretKey secretKey = await keyGenerator.deriveKeyFromPassword(password: password, nonce: salt);
- final Uint8List keyBytes = Uint8List.fromList(await secretKey.extractBytes());
- final Key key = Key(keyBytes);
-
- final encrypter = Encrypter(AES(key, mode: aesMode, padding: padding));
- final iv = IV.fromBase64(ivBase64);
- final String decryptedString;
- try {
- final decrypted = encrypter.decryptBytes(Encrypted(data), iv: iv);
- decryptedString = utf8.decode(decrypted);
- } catch (e) {
- throw Exception('Wrong password or corrupted data');
+ final Mac? mac;
+ // final String? padding;
+
+ final Cipher cypher;
+
+ const AesEncrypted._({
+ required this.kdf,
+ required this.salt,
+ required this.data,
+ required this.iv,
+ this.mac,
+ required this.cypher,
+ });
+
+ /// If mac is not provided, it will be extracted from the last 16 bytes of the data
+ /// This is the default of AES encryption.
+ factory AesEncrypted({
+ required Uint8List data,
+ required Uint8List salt,
+ required Uint8List iv,
+ Mac? mac,
+ required KdfAlgorithm kdf,
+ required Cipher cypher,
+ }) {
+ if (mac == null) {
+ mac = Mac(data.sublist(data.length - 16, data.length));
+ data = data.sublist(0, data.length - 16);
}
- return decryptedString;
+ return AesEncrypted._(mac: mac, kdf: kdf, cypher: cypher, salt: salt, iv: iv, data: data);
+ }
+
+ /// Encrypts the data using AES-GCM with 256 bits.
+ /// Iterations are set to 100,000 (one hundred thousand).
+ /// The password is used to derive the key using PBKDF2.
+ /// When the salt or iv is not provided, it is generated randomly. (16 bytes each)
+ /// The mac is calculated by the cypher.
+ /// The data is concatenated with the iv and mac.
+ /// The result is returned as an AesEncrypted object.
+ static Future encrypt({
+ required String data,
+ required String password,
+ Uint8List? salt,
+ Uint8List? iv,
+ }) async {
+ final plainBytes = utf8.encode(data);
+ final cypher = AesGcm.with256bits();
+ final kdf = Pbkdf2(
+ macAlgorithm: defaultMacAlgorithm,
+ iterations: defaultIterations,
+ bits: defaultBits,
+ );
+ salt ??= Uint8List.fromList(List.generate(16, (index) => Random.secure().nextInt(256)));
+ iv ??= Uint8List.fromList(List.generate(16, (index) => Random.secure().nextInt(256)));
+ final secretKey = await kdf.deriveKeyFromPassword(password: password, nonce: salt);
+ final secretBox = await cypher.encrypt(plainBytes, secretKey: secretKey, nonce: iv);
+ final encryptedData = secretBox.concatenation(nonce: false, mac: false);
+ return AesEncrypted._(
+ cypher: cypher,
+ kdf: kdf,
+ salt: salt,
+ iv: iv,
+ data: encryptedData,
+ mac: secretBox.mac,
+ );
+ }
+
+ Future decrypt(String password) async {
+ final SecretKey secretKey = await _deriveKey(password);
+ final SecretBox secretBox = SecretBox(data, nonce: iv, mac: mac ?? Mac.empty);
+ final decrypted = await cypher.decrypt(secretBox, secretKey: secretKey);
+ return Uint8List.fromList(decrypted);
+ }
+
+ Future decryptToString(String password) async {
+ final decrypted = await decrypt(password);
+ return utf8.decode(decrypted);
+ }
+
+ Future _deriveKey(String password) async {
+ return await kdf.deriveKeyFromPassword(password: password, nonce: salt);
+ }
+
+ static AesEncrypted fromJson(Map json) {
+ return AesEncrypted(
+ data: base64Decode(json['data']),
+ salt: base64Decode(json['salt']),
+ iv: base64Decode(json['iv']),
+ mac: Mac(base64Decode(json['mac'])),
+ kdf: KdfAlgorithmX.fromJson(json['kdf']),
+ cypher: CipherX.fromJson(json['cypher']),
+ );
+ }
+
+ Map toJson() {
+ return {
+ 'data': base64Encode(data),
+ 'salt': base64Encode(salt),
+ 'iv': base64Encode(iv),
+ 'mac': base64Encode(mac?.bytes ?? Uint8List(0)),
+ 'kdf': kdf.toJson(),
+ 'cypher': cypher.toJson(),
+ };
+ }
+}
+
+/* ////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////// SERIALIZATION EXTENSIONS ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////// */
+
+extension MacAlgorithmX on MacAlgorithm {
+ static MacAlgorithm fromJson(Map json) {
+ final algorithm = json['algorithm'];
+ return switch (algorithm) {
+ 'Hmac' => HmacX.fromJson(json),
+ _ => throw UnsupportedError('Unsupported MAC algorithm: $algorithm'),
+ };
+ }
+
+ Map toJson() => switch (runtimeType) {
+ const (DartHmac) => (this as DartHmac).toJson(),
+ _ => throw UnsupportedError('Unsupported MAC algorithm: $this'),
+ };
+}
+
+extension HmacX on Hmac {
+ static Hmac fromJson(Map json) {
+ final hashAlgorithm = HashAlgorithmX.fromJson(json['hashAlgorithm']);
+ return Hmac(hashAlgorithm);
+ }
+
+ Map toJson() => {
+ 'algorithm': 'Hmac',
+ 'hashAlgorithm': hashAlgorithm.toJson(),
+ };
+}
+
+extension HashAlgorithmX on HashAlgorithm {
+ static HashAlgorithm fromJson(Map json) {
+ final algorithm = json['algorithm'];
+ return switch (algorithm) {
+ 'DartSha256' => const DartSha256(),
+ 'DartSha512' => const DartSha512(),
+ _ => throw UnsupportedError('Unsupported hash algorithm: $algorithm'),
+ };
+ }
+
+ Map toJson() => {
+ 'algorithm': runtimeType.toString(),
+ };
+}
+
+extension KdfAlgorithmX on KdfAlgorithm {
+ static KdfAlgorithm fromJson(Map json) {
+ final algorithm = json['algorithm'];
+ return switch (algorithm) {
+ 'Pbkdf2' => Pbkdf2X.fromJson(json),
+ _ => throw UnsupportedError('Unsupported KDF algorithm: $algorithm'),
+ };
+ }
+
+ Map toJson() => switch (runtimeType) {
+ const (DartPbkdf2) => (this as DartPbkdf2).toJson(),
+ _ => throw UnsupportedError('Unsupported KDF algorithm: $this'),
+ };
+}
+
+extension Pbkdf2X on Pbkdf2 {
+ static Pbkdf2 fromJson(Map json) {
+ final macAlgorithm = MacAlgorithmX.fromJson(json['macAlgorithm']);
+ final iterations = json['iterations'] as int;
+ final bits = json['bits'] as int;
+ return Pbkdf2(
+ macAlgorithm: macAlgorithm,
+ iterations: iterations,
+ bits: bits,
+ );
+ }
+
+ Map toJson() => {
+ 'algorithm': 'Pbkdf2',
+ 'macAlgorithm': macAlgorithm.toJson(),
+ 'iterations': iterations,
+ 'bits': bits,
+ };
+}
+
+extension CipherX on Cipher {
+ static Cipher fromJson(Map json) {
+ final algorithm = json['algorithm'];
+ return switch (algorithm) {
+ 'AesGcm' => AesGcmX.fromJson(json),
+ 'AesCbc' => AesCbcX.fromJson(json),
+ _ => throw UnsupportedError('Unsupported cipher algorithm: $algorithm'),
+ };
+ }
+
+ Map toJson() => switch (runtimeType) {
+ const (DartAesGcm) => (this as DartAesGcm).toJson(),
+ const (DartAesCbc) => (this as DartAesCbc).toJson(),
+ _ => throw UnsupportedError('Unsupported cipher algorithm: $this'),
+ };
+}
+
+extension AesGcmX on AesGcm {
+ static AesGcm fromJson(Map json) {
+ final secretKeyLength = json['secretKeyLength'];
+ return switch (secretKeyLength) {
+ 16 => AesGcm.with128bits(),
+ 24 => AesGcm.with192bits(),
+ 32 => AesGcm.with256bits(),
+ _ => throw UnsupportedError('Unsupported secret key length: $secretKeyLength'),
+ };
+ }
+
+ Map toJson() {
+ return {
+ 'algorithm': 'AesGcm',
+ 'secretKeyLength': secretKeyLength,
+ };
+ }
+}
+
+extension AesCbcX on AesCbc {
+ static AesCbc fromJson(Map json) {
+ final secretKeyLength = json['secretKeyLength'];
+ final macAlgorithm = json['macAlgorithm'] != null ? MacAlgorithmX.fromJson(json['macAlgorithm']) : Hmac.sha256();
+ final paddingAlgorithm = json['paddingAlgorithm'] != null ? PaddingAlgorithmX.fromString(json['paddingAlgorithm']) : PaddingAlgorithm.pkcs7;
+ return switch (secretKeyLength) {
+ 16 => AesCbc.with128bits(macAlgorithm: macAlgorithm, paddingAlgorithm: paddingAlgorithm),
+ 24 => AesCbc.with192bits(macAlgorithm: macAlgorithm, paddingAlgorithm: paddingAlgorithm),
+ 32 => AesCbc.with256bits(macAlgorithm: macAlgorithm, paddingAlgorithm: paddingAlgorithm),
+ _ => throw UnsupportedError('Unsupported secret key length: $secretKeyLength'),
+ };
+ }
+
+ Map toJson() {
+ return {
+ 'algorithm': 'AesCbc',
+ 'secretKeyLength': secretKeyLength,
+ 'macAlgorithm': macAlgorithm.toString(),
+ 'paddingAlgorithm': paddingAlgorithm.toString(),
+ };
+ }
+}
+
+extension PaddingAlgorithmX on PaddingAlgorithm {
+ static PaddingAlgorithm fromString(String string) {
+ return switch (string) {
+ 'PaddingAlgorithm.pkcs7' => PaddingAlgorithm.pkcs7,
+ 'PaddingAlgorithm.zero' => PaddingAlgorithm.zero,
+ _ => throw UnsupportedError('Unsupported padding algorithm: $string')
+ };
}
}
diff --git a/lib/model/encryption/token_encryption.dart b/lib/model/encryption/token_encryption.dart
new file mode 100644
index 000000000..ffc585675
--- /dev/null
+++ b/lib/model/encryption/token_encryption.dart
@@ -0,0 +1,38 @@
+import 'dart:convert';
+
+import '../../processors/scheme_processors/token_import_scheme_processors/privacyidea_authenticator_qr_processor.dart';
+import '../tokens/token.dart';
+import 'aes_encrypted.dart';
+
+class TokenEncryption {
+ static Future encrypt({required Iterable tokens, required String password}) async {
+ final jsonsList = tokens.map((e) => e.toJson()).toList();
+ final encoded = json.encode(jsonsList);
+ final encrypted = (await AesEncrypted.encrypt(data: encoded, password: password)).toJson();
+ return jsonEncode(encrypted);
+ }
+
+ static Future> decrypt({required String encryptedTokens, required String password}) async {
+ final json = jsonDecode(encryptedTokens);
+ final tokenJsonString = await AesEncrypted.fromJson(json).decryptToString(password);
+ final tokenJsonsList = jsonDecode(tokenJsonString) as List;
+ return tokenJsonsList.map((e) => Token.fromJson(e)).toList();
+ }
+
+ static Uri generateQrCodeUri({required Token token}) {
+ final tokenJson = token.toJson();
+ final encoded = json.encode(tokenJson);
+ final bytes = utf8.encode(encoded);
+ final base64 = base64Url.encode(bytes);
+ final uri = Uri.parse('${PrivacyIDEAAuthenticatorQrProcessor.scheme}://${PrivacyIDEAAuthenticatorQrProcessor.host}?data=$base64');
+ return uri;
+ }
+
+ static Token fromQrCodeUri(Uri uri) {
+ final base64String = uri.queryParameters['data'];
+ final bytes = base64Url.decode(base64String!);
+ final jsonString = utf8.decode(bytes);
+ final tokenJson = json.decode(jsonString) as Map;
+ return Token.fromJson(tokenJson);
+ }
+}
diff --git a/lib/model/encryption/uint_8_buffer.dart b/lib/model/encryption/uint_8_buffer.dart
new file mode 100644
index 000000000..804717f31
--- /dev/null
+++ b/lib/model/encryption/uint_8_buffer.dart
@@ -0,0 +1,50 @@
+import 'dart:typed_data';
+
+class Uint8Buffer {
+ int currentPos = 0;
+ Uint8List data;
+ Uint8Buffer({required this.data});
+ factory Uint8Buffer.fromList(List list) {
+ return Uint8Buffer(data: Uint8List.fromList(list));
+ }
+
+ /// Writes [bytes] to the buffer
+ void writeBytes(Uint8List bytes) {
+ data = Uint8List.fromList([...data, ...bytes]);
+ }
+
+ /// Reads [length] bytes from the current position
+ /// and moves the position forward
+ /// If [length] is out of bounds, it will return the rest of the buffer
+ Uint8List readBytes(int length) {
+ var nextPos = currentPos + length;
+ if (nextPos > data.length) nextPos = data.length;
+ final bytes = data.sublist(currentPos, nextPos);
+ currentPos = nextPos;
+ return bytes;
+ }
+
+ /// Reads all bytes from the current position to the end of the buffer
+ /// If [left] is provided, it will leave [left] bytes at the end
+ /// and return the rest
+ /// If [left] is out of bounds, it will return an empty list
+ Uint8List readBytesToEnd({int left = 0}) {
+ if (left < 0) left = 0;
+ var nextPos = data.length - left;
+ if (nextPos < currentPos) nextPos = currentPos;
+ final bytes = data.sublist(currentPos, data.length - left);
+ currentPos = data.length - left;
+ return bytes;
+ }
+
+ /// Moves the current position to [pos]
+ /// If [pos] is out of bounds, it will move to the closest bound
+ void moveCurrentPos(int pos) {
+ if (pos > data.length) {
+ pos = data.length;
+ } else if (pos < 0) {
+ pos = 0;
+ }
+ currentPos = pos;
+ }
+}
diff --git a/lib/model/enums/algorithms.dart b/lib/model/enums/algorithms.dart
index 41ffe4faf..fa09abb40 100644
--- a/lib/model/enums/algorithms.dart
+++ b/lib/model/enums/algorithms.dart
@@ -1,17 +1,7 @@
// ignore_for_file: constant_identifier_names
-
-import 'package:otp/otp.dart' as otp_library;
-
+// Do not rename or remove values, they are used for serialization. Only add new values.
enum Algorithms {
SHA1,
SHA256,
SHA512,
}
-
-extension AlgorithmsExtension on Algorithms {
- otp_library.Algorithm get otpLibraryAlgorithm => switch (this) {
- Algorithms.SHA1 => otp_library.Algorithm.SHA1,
- Algorithms.SHA256 => otp_library.Algorithm.SHA256,
- Algorithms.SHA512 => otp_library.Algorithm.SHA512,
- };
-}
diff --git a/lib/model/enums/app_feature.dart b/lib/model/enums/app_feature.dart
index 2e39e73a8..11c4e6f17 100644
--- a/lib/model/enums/app_feature.dart
+++ b/lib/model/enums/app_feature.dart
@@ -1,14 +1,4 @@
+// Do not rename or remove values, they are used for serialization. Only add new values.
enum AppFeature {
patchNotes,
}
-
-extension AppFeatureX on AppFeature {
- String get name => switch (this) {
- AppFeature.patchNotes => 'patchNotes',
- };
-
- static AppFeature fromName(String featureString) => switch (featureString) {
- 'patchNotes' => AppFeature.patchNotes,
- _ => throw ArgumentError('Invalid feature string: $featureString'),
- };
-}
diff --git a/lib/model/enums/day_passoword_token_view_mode.dart b/lib/model/enums/day_password_token_view_mode.dart
similarity index 54%
rename from lib/model/enums/day_passoword_token_view_mode.dart
rename to lib/model/enums/day_password_token_view_mode.dart
index 5196afd95..e06569c57 100644
--- a/lib/model/enums/day_passoword_token_view_mode.dart
+++ b/lib/model/enums/day_password_token_view_mode.dart
@@ -1,5 +1,5 @@
// ignore_for_file: constant_identifier_names
-
+// Do not rename or remove values, they are used for serialization. Only add new values.
enum DayPasswordTokenViewMode {
VALIDFOR,
VALIDUNTIL,
diff --git a/lib/model/enums/introduction.dart b/lib/model/enums/introduction.dart
index 5672bfd63..61a3cd8ae 100644
--- a/lib/model/enums/introduction.dart
+++ b/lib/model/enums/introduction.dart
@@ -1,69 +1,13 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:json_annotation/json_annotation.dart';
-
-import '../../l10n/app_localizations.dart';
-import '../../utils/riverpod_providers.dart';
-import '../states/introduction_state.dart';
-
-// Do not rename or remove JsonValue values, they are used for serialization. Only add new values.
+// Do not rename or remove values, they are used for serialization. Only add new values.
enum Introduction {
- @JsonValue('introductionScreen')
introductionScreen, // 1st start
- @JsonValue('scanQrCode')
scanQrCode, // 1st start && introductionScreen
- @JsonValue('addManually')
- addTokenManually, // 1st start && scanQrCode
- @JsonValue('tokenSwipe')
+ addManually, // 1st start && scanQrCode
tokenSwipe, // 1st token
- @JsonValue('editToken')
editToken, // 1st token && tokenSwipe
- @JsonValue('lockToken')
lockToken, // 1st token && editToken
- @JsonValue('dragToken')
dragToken, // 2nd token && tokenSwipe
- @JsonValue('addFolder')
addFolder, // 3 tokens && 0 groups
- @JsonValue('pollForChallenges')
pollForChallenges, // 1st push token && lockToken
- @JsonValue('hidePushTokens')
hidePushTokens, // hiding is enabled
}
-
-extension IntroductionExtension on Introduction {
- bool isConditionFulfilled(WidgetRef ref, IntroductionState state) => switch (this) {
- Introduction.introductionScreen => state.isUncompleted(Introduction.introductionScreen),
- Introduction.scanQrCode => state.isCompleted(Introduction.introductionScreen) && state.isUncompleted(Introduction.scanQrCode),
- Introduction.addTokenManually => state.isCompleted(Introduction.scanQrCode) && state.isUncompleted(Introduction.addTokenManually),
- Introduction.tokenSwipe =>
- ref.watch(tokenProvider).tokens.isNotEmpty && state.isCompleted(Introduction.addTokenManually) && state.isUncompleted(Introduction.tokenSwipe),
- Introduction.editToken => state.isCompleted(Introduction.tokenSwipe) && state.isUncompleted(Introduction.editToken),
- Introduction.lockToken => state.isCompleted(Introduction.editToken) && state.isUncompleted(Introduction.lockToken),
- Introduction.dragToken =>
- ref.watch(tokenProvider).tokens.length >= 2 && state.isCompleted(Introduction.tokenSwipe) && state.isUncompleted(Introduction.dragToken),
- Introduction.addFolder => ref.watch(tokenProvider).tokens.length >= 3 &&
- state.isCompleted(Introduction.dragToken) &&
- state.isUncompleted(Introduction.addFolder) &&
- Introduction.dragToken.isConditionFulfilled(ref, state) == false,
- Introduction.pollForChallenges => ref.watch(tokenProvider).pushTokens.firstOrNull?.isRolledOut == true &&
- state.isCompleted(Introduction.tokenSwipe) &&
- state.isUncompleted(Introduction.pollForChallenges) &&
- Introduction.dragToken.isConditionFulfilled(ref, state) == false &&
- Introduction.addFolder.isConditionFulfilled(ref, state) == false,
- Introduction.hidePushTokens =>
- ref.watch(settingsProvider).hidePushTokens && state.isCompleted(Introduction.pollForChallenges) && state.isUncompleted(Introduction.hidePushTokens),
- };
-
- String hintText(BuildContext context) => switch (this) {
- Introduction.introductionScreen => '',
- Introduction.scanQrCode => AppLocalizations.of(context)!.introScanQrCode,
- Introduction.addTokenManually => AppLocalizations.of(context)!.introAddTokenManually,
- Introduction.tokenSwipe => AppLocalizations.of(context)!.introTokenSwipe,
- Introduction.editToken => AppLocalizations.of(context)!.introEditToken,
- Introduction.lockToken => AppLocalizations.of(context)!.introLockToken,
- Introduction.dragToken => AppLocalizations.of(context)!.introDragToken,
- Introduction.addFolder => AppLocalizations.of(context)!.introAddFolder,
- Introduction.pollForChallenges => AppLocalizations.of(context)!.introPollForChallenges,
- Introduction.hidePushTokens => AppLocalizations.of(context)!.introHidePushTokens,
- };
-}
diff --git a/lib/model/enums/patch_note_type.dart b/lib/model/enums/patch_note_type.dart
index b5fa16544..7e917bb19 100644
--- a/lib/model/enums/patch_note_type.dart
+++ b/lib/model/enums/patch_note_type.dart
@@ -1,15 +1,5 @@
-import '../../l10n/app_localizations.dart';
-
enum PatchNoteType {
newFeature,
improvement,
bugFix,
}
-
-extension PatchNoteTypeExtension on PatchNoteType {
- String getName(AppLocalizations localizations) => switch (this) {
- PatchNoteType.newFeature => localizations.patchNotesNewFeatures,
- PatchNoteType.improvement => localizations.patchNotesImprovements,
- PatchNoteType.bugFix => localizations.patchNotesBugFixes,
- };
-}
diff --git a/lib/model/enums/push_token_rollout_state.dart b/lib/model/enums/push_token_rollout_state.dart
index a3598017b..e4e34399a 100644
--- a/lib/model/enums/push_token_rollout_state.dart
+++ b/lib/model/enums/push_token_rollout_state.dart
@@ -1,7 +1,4 @@
-import 'package:flutter/material.dart';
-
-import '../../l10n/app_localizations.dart';
-
+// Do not rename or remove values, they are used for serialization. Only add new values.
enum PushTokenRollOutState {
rolloutNotStarted,
generatingRSAKeyPair,
@@ -12,26 +9,3 @@ enum PushTokenRollOutState {
parsingResponseFailed,
rolloutComplete,
}
-
-extension PushTokenRollOutStateExtension on PushTokenRollOutState {
- bool get rollOutInProgress => switch (this) {
- PushTokenRollOutState.rolloutNotStarted => false,
- PushTokenRollOutState.generatingRSAKeyPair => true,
- PushTokenRollOutState.generatingRSAKeyPairFailed => false,
- PushTokenRollOutState.sendRSAPublicKey => true,
- PushTokenRollOutState.sendRSAPublicKeyFailed => false,
- PushTokenRollOutState.parsingResponse => true,
- PushTokenRollOutState.parsingResponseFailed => false,
- PushTokenRollOutState.rolloutComplete => false,
- };
- String rolloutMsg(BuildContext context) => switch (this) {
- PushTokenRollOutState.rolloutNotStarted => AppLocalizations.of(context)!.rollingOut,
- PushTokenRollOutState.generatingRSAKeyPair => AppLocalizations.of(context)!.generatingRSAKeyPair,
- PushTokenRollOutState.generatingRSAKeyPairFailed => AppLocalizations.of(context)!.generatingRSAKeyPairFailed,
- PushTokenRollOutState.sendRSAPublicKey => AppLocalizations.of(context)!.sendingRSAPublicKey,
- PushTokenRollOutState.sendRSAPublicKeyFailed => AppLocalizations.of(context)!.sendingRSAPublicKeyFailed,
- PushTokenRollOutState.parsingResponse => AppLocalizations.of(context)!.parsingResponse,
- PushTokenRollOutState.parsingResponseFailed => AppLocalizations.of(context)!.parsingResponseFailed,
- PushTokenRollOutState.rolloutComplete => AppLocalizations.of(context)!.rolloutCompleted,
- };
-}
diff --git a/lib/model/enums/token_import_type.dart b/lib/model/enums/token_import_type.dart
index 47ea211aa..0f92f2e59 100644
--- a/lib/model/enums/token_import_type.dart
+++ b/lib/model/enums/token_import_type.dart
@@ -1,27 +1,7 @@
-import 'package:flutter/material.dart';
-
-import '../../l10n/app_localizations.dart';
-
+// Do not rename or remove values, they are used for serialization. Only add new values.
enum TokenImportType {
backupFile,
qrScan,
qrFile,
link,
}
-
-extension TokenImportTypeExtension on TokenImportType {
- String get name => toString().split('.').last;
- IconData get icon => switch (this) {
- const (TokenImportType.backupFile) => Icons.file_present,
- const (TokenImportType.qrScan) => Icons.qr_code_scanner,
- const (TokenImportType.qrFile) => Icons.qr_code_2,
- const (TokenImportType.link) => Icons.link,
- };
-
- String getButtonText(BuildContext context) => switch (this) {
- const (TokenImportType.backupFile) => AppLocalizations.of(context)!.selectFile,
- const (TokenImportType.qrScan) => AppLocalizations.of(context)!.scanQrCode,
- const (TokenImportType.qrFile) => AppLocalizations.of(context)!.selectFile,
- const (TokenImportType.link) => AppLocalizations.of(context)!.enterLink,
- };
-}
diff --git a/lib/model/enums/token_origin_source_type.dart b/lib/model/enums/token_origin_source_type.dart
index 99cc7ca8d..c24d1a34a 100644
--- a/lib/model/enums/token_origin_source_type.dart
+++ b/lib/model/enums/token_origin_source_type.dart
@@ -1,19 +1,11 @@
-import '../../mains/main_netknights.dart';
-import '../token_origin.dart';
-import '../tokens/token.dart';
-
+// Do not rename or remove values, they are used for serialization. Only add new values.
enum TokenOriginSourceType {
backupFile,
qrScan,
qrFile,
+ qrScanImport,
link,
+ linkImport,
manually,
unknown,
}
-
-extension TokenSourceTypeExtension on TokenOriginSourceType {
- TokenOriginData toTokenOrigin({String data = '', String? appName}) =>
- TokenOriginData(source: this, data: data, appName: appName ?? PrivacyIDEAAuthenticator.currentCustomization?.appName);
-
- Token addOriginToToken({required Token token, required String data, String? appName}) => token.copyWith(origin: toTokenOrigin(data: data, appName: appName));
-}
diff --git a/lib/model/enums/token_types.dart b/lib/model/enums/token_types.dart
index 0b3ab49ed..a4756ce86 100644
--- a/lib/model/enums/token_types.dart
+++ b/lib/model/enums/token_types.dart
@@ -1,8 +1,9 @@
// ignore_for_file: constant_identifier_names
-
+// Do not rename or remove values, they are used for serialization. Only add new values.
enum TokenTypes {
HOTP,
TOTP,
PIPUSH,
DAYPASSWORD,
+ STEAM,
}
diff --git a/lib/model/extensions/color_extension.dart b/lib/model/extensions/color_extension.dart
new file mode 100644
index 000000000..0c3d53011
--- /dev/null
+++ b/lib/model/extensions/color_extension.dart
@@ -0,0 +1,12 @@
+import 'dart:ui';
+
+extension ColorExtension on Color {
+ Color mixWith(Color other) => Color.fromARGB(
+ (alpha + other.alpha) ~/ 2.clamp(0, 255),
+ (red + other.red) ~/ 2.clamp(0, 255),
+ (green + other.green) ~/ 2.clamp(0, 255),
+ (blue + other.blue) ~/ 2.clamp(0, 255),
+ );
+
+ Color inverted() => Color.fromARGB(alpha, 255 - red, 255 - green, 255 - blue);
+}
diff --git a/lib/model/extensions/enum_extension.dart b/lib/model/extensions/enum_extension.dart
index 2dba81809..301f32513 100644
--- a/lib/model/extensions/enum_extension.dart
+++ b/lib/model/extensions/enum_extension.dart
@@ -1,14 +1,3 @@
extension EnumExtension on Enum {
- String get asString => toString().split('.').last;
-
- static Enum fromString(String string, List values) {
- for (var value in values) {
- if (value.asString.toLowerCase() == string.toLowerCase()) {
- return value;
- }
- }
- throw ArgumentError('Invalid token source type string');
- }
-
- bool isString(String encoding) => encoding.toLowerCase() == asString.toLowerCase();
+ bool isName(String enumName, {bool caseSensitive = true}) => caseSensitive ? name == enumName : name.toLowerCase() == enumName.toLowerCase();
}
diff --git a/lib/model/extensions/enums/algorithms_extension.dart b/lib/model/extensions/enums/algorithms_extension.dart
new file mode 100644
index 000000000..5402adc3e
--- /dev/null
+++ b/lib/model/extensions/enums/algorithms_extension.dart
@@ -0,0 +1,38 @@
+import 'package:otp/otp.dart';
+
+import '../../enums/algorithms.dart';
+
+extension AlgorithmsX on Algorithms {
+ /// Generates a Time-based one time password code and return as a 0 padded string.
+ /// DateTime should be the current time.
+ /// Ig isGoogle is true, the secret will be decoded as base32, otherwise it will be decoded as utf8.
+ String generateTOTPCodeString({
+ required String secret,
+ required DateTime time,
+ required int length,
+ required Duration interval,
+ bool isGoogle = true,
+ }) =>
+ switch (this) {
+ Algorithms.SHA1 => OTP.generateTOTPCodeString(secret, time.millisecondsSinceEpoch,
+ length: length, interval: interval.inSeconds, algorithm: Algorithm.SHA1, isGoogle: isGoogle),
+ Algorithms.SHA256 => OTP.generateTOTPCodeString(secret, time.millisecondsSinceEpoch,
+ length: length, interval: interval.inSeconds, algorithm: Algorithm.SHA256, isGoogle: isGoogle),
+ Algorithms.SHA512 => OTP.generateTOTPCodeString(secret, time.millisecondsSinceEpoch,
+ length: length, interval: interval.inSeconds, algorithm: Algorithm.SHA512, isGoogle: isGoogle),
+ };
+
+ /// Generates a Counter-based one time password code and return as a 0 padded string.
+ /// If isGoogle is true, the secret will be decoded as base32, otherwise it will be decoded as utf8.
+ String generateHOTPCodeString({
+ required String secret,
+ required int counter,
+ required int length,
+ bool isGoogle = true,
+ }) =>
+ switch (this) {
+ Algorithms.SHA1 => OTP.generateHOTPCodeString(secret, counter, length: length, algorithm: Algorithm.SHA1, isGoogle: isGoogle),
+ Algorithms.SHA256 => OTP.generateHOTPCodeString(secret, counter, length: length, algorithm: Algorithm.SHA256, isGoogle: isGoogle),
+ Algorithms.SHA512 => OTP.generateHOTPCodeString(secret, counter, length: length, algorithm: Algorithm.SHA512, isGoogle: isGoogle),
+ };
+}
diff --git a/lib/model/extensions/enums/encodings_extension.dart b/lib/model/extensions/enums/encodings_extension.dart
new file mode 100644
index 000000000..e176c9ccf
--- /dev/null
+++ b/lib/model/extensions/enums/encodings_extension.dart
@@ -0,0 +1,57 @@
+import 'dart:convert';
+
+import 'package:base32/base32.dart';
+import 'package:flutter/foundation.dart';
+import 'package:hex/hex.dart';
+
+import '../../enums/encodings.dart';
+
+extension EncodingsX on Encodings {
+ String encode(Uint8List data) => switch (this) {
+ Encodings.none => utf8.decode(data),
+ Encodings.base32 => base32.encode(data),
+ Encodings.hex => HEX.encode(data),
+ };
+
+ String encodeStringTo(Encodings encoding, String data) => encoding.encode(decode(data));
+
+ Uint8List decode(String string) => switch (this) {
+ Encodings.none => utf8.encode(string),
+ Encodings.base32 => Uint8List.fromList(base32.decode(string)),
+ Encodings.hex => Uint8List.fromList(HEX.decode(string)),
+ };
+
+ bool isValidEncoding(String string) {
+ try {
+ decode(string);
+ return true;
+ } catch (_) {
+ return false;
+ }
+ }
+
+ bool isInvalidEncoding(String string) {
+ try {
+ decode(string);
+ return false;
+ } catch (_) {
+ return true;
+ }
+ }
+
+ Uint8List? tryDecode(String string) {
+ try {
+ return decode(string);
+ } catch (_) {
+ return null;
+ }
+ }
+
+ String? tryEncode(Uint8List data) {
+ try {
+ return encode(data);
+ } catch (_) {
+ return null;
+ }
+ }
+}
diff --git a/lib/model/extensions/enums/introduction_extension.dart b/lib/model/extensions/enums/introduction_extension.dart
new file mode 100644
index 000000000..cc319b1fb
--- /dev/null
+++ b/lib/model/extensions/enums/introduction_extension.dart
@@ -0,0 +1,46 @@
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+import '../../../l10n/app_localizations.dart';
+import '../../../utils/riverpod_providers.dart';
+import '../../enums/introduction.dart';
+import '../../states/introduction_state.dart';
+
+extension IntroductionX on Introduction {
+ /// Checks if the condition for the given state is fulfilled.
+ /// Given ref might be watched to acces the state of different providers.
+ bool isConditionFulfilled(WidgetRef ref, IntroductionState state) => switch (this) {
+ Introduction.introductionScreen => state.isUncompleted(Introduction.introductionScreen),
+ Introduction.scanQrCode => state.isUncompleted(Introduction.scanQrCode),
+ Introduction.addManually => state.isCompleted(Introduction.scanQrCode) && state.isUncompleted(Introduction.addManually),
+ Introduction.tokenSwipe =>
+ ref.watch(tokenProvider).tokens.isNotEmpty && state.isCompleted(Introduction.addManually) && state.isUncompleted(Introduction.tokenSwipe),
+ Introduction.editToken => state.isCompleted(Introduction.tokenSwipe) && state.isUncompleted(Introduction.editToken),
+ Introduction.lockToken => state.isCompleted(Introduction.editToken) && state.isUncompleted(Introduction.lockToken),
+ Introduction.dragToken =>
+ ref.watch(tokenProvider).tokens.length >= 2 && state.isCompleted(Introduction.tokenSwipe) && state.isUncompleted(Introduction.dragToken),
+ Introduction.addFolder => ref.watch(tokenProvider).tokens.length >= 3 &&
+ state.isCompleted(Introduction.dragToken) &&
+ state.isUncompleted(Introduction.addFolder) &&
+ Introduction.dragToken.isConditionFulfilled(ref, state) == false,
+ Introduction.pollForChallenges => ref.watch(tokenProvider).pushTokens.firstOrNull?.isRolledOut == true &&
+ state.isCompleted(Introduction.tokenSwipe) &&
+ state.isUncompleted(Introduction.pollForChallenges) &&
+ Introduction.dragToken.isConditionFulfilled(ref, state) == false &&
+ Introduction.addFolder.isConditionFulfilled(ref, state) == false,
+ Introduction.hidePushTokens =>
+ ref.watch(settingsProvider).hidePushTokens && state.isCompleted(Introduction.pollForChallenges) && state.isUncompleted(Introduction.hidePushTokens),
+ };
+
+ String hintText(AppLocalizations localizations) => switch (this) {
+ Introduction.introductionScreen => 'Not implemented',
+ Introduction.scanQrCode => localizations.introScanQrCode,
+ Introduction.addManually => localizations.introAddTokenManually,
+ Introduction.tokenSwipe => localizations.introTokenSwipe,
+ Introduction.editToken => localizations.introEditToken,
+ Introduction.lockToken => localizations.introLockToken,
+ Introduction.dragToken => localizations.introDragToken,
+ Introduction.addFolder => localizations.introAddFolder,
+ Introduction.pollForChallenges => localizations.introPollForChallenges,
+ Introduction.hidePushTokens => localizations.introHidePushTokens,
+ };
+}
diff --git a/lib/model/extensions/enums/patch_note_type_extension.dart b/lib/model/extensions/enums/patch_note_type_extension.dart
new file mode 100644
index 000000000..adad05302
--- /dev/null
+++ b/lib/model/extensions/enums/patch_note_type_extension.dart
@@ -0,0 +1,10 @@
+import '../../../l10n/app_localizations.dart';
+import '../../enums/patch_note_type.dart';
+
+extension PatchNoteTypeX on PatchNoteType {
+ String localizedName(AppLocalizations localizations) => switch (this) {
+ PatchNoteType.newFeature => localizations.patchNotesNewFeatures,
+ PatchNoteType.improvement => localizations.patchNotesImprovements,
+ PatchNoteType.bugFix => localizations.patchNotesBugFixes,
+ };
+}
diff --git a/lib/model/extensions/enums/push_token_rollout_state_extension.dart b/lib/model/extensions/enums/push_token_rollout_state_extension.dart
new file mode 100644
index 000000000..925ecbd64
--- /dev/null
+++ b/lib/model/extensions/enums/push_token_rollout_state_extension.dart
@@ -0,0 +1,37 @@
+import '../../../l10n/app_localizations.dart';
+import '../../enums/push_token_rollout_state.dart';
+
+extension PushTokenRollOutStateX on PushTokenRollOutState {
+ bool get rollOutInProgress => switch (this) {
+ PushTokenRollOutState.rolloutNotStarted => false,
+ PushTokenRollOutState.generatingRSAKeyPair => true,
+ PushTokenRollOutState.generatingRSAKeyPairFailed => false,
+ PushTokenRollOutState.sendRSAPublicKey => true,
+ PushTokenRollOutState.sendRSAPublicKeyFailed => false,
+ PushTokenRollOutState.parsingResponse => true,
+ PushTokenRollOutState.parsingResponseFailed => false,
+ PushTokenRollOutState.rolloutComplete => false,
+ };
+
+ PushTokenRollOutState getFailed() => switch (this) {
+ PushTokenRollOutState.rolloutNotStarted => PushTokenRollOutState.rolloutNotStarted,
+ PushTokenRollOutState.generatingRSAKeyPair => PushTokenRollOutState.generatingRSAKeyPairFailed,
+ PushTokenRollOutState.generatingRSAKeyPairFailed => PushTokenRollOutState.generatingRSAKeyPairFailed,
+ PushTokenRollOutState.sendRSAPublicKey => PushTokenRollOutState.sendRSAPublicKeyFailed,
+ PushTokenRollOutState.sendRSAPublicKeyFailed => PushTokenRollOutState.sendRSAPublicKeyFailed,
+ PushTokenRollOutState.parsingResponse => PushTokenRollOutState.parsingResponseFailed,
+ PushTokenRollOutState.parsingResponseFailed => PushTokenRollOutState.parsingResponseFailed,
+ PushTokenRollOutState.rolloutComplete => PushTokenRollOutState.rolloutComplete,
+ };
+
+ String rolloutMsg(AppLocalizations localizations) => switch (this) {
+ PushTokenRollOutState.rolloutNotStarted => localizations.rollingOut,
+ PushTokenRollOutState.generatingRSAKeyPair => localizations.generatingRSAKeyPair,
+ PushTokenRollOutState.generatingRSAKeyPairFailed => localizations.generatingRSAKeyPairFailed,
+ PushTokenRollOutState.sendRSAPublicKey => localizations.sendingRSAPublicKey,
+ PushTokenRollOutState.sendRSAPublicKeyFailed => localizations.sendingRSAPublicKeyFailed,
+ PushTokenRollOutState.parsingResponse => localizations.parsingResponse,
+ PushTokenRollOutState.parsingResponseFailed => localizations.parsingResponseFailed,
+ PushTokenRollOutState.rolloutComplete => localizations.rolloutCompleted,
+ };
+}
diff --git a/lib/model/extensions/enums/token_import_type_extension.dart b/lib/model/extensions/enums/token_import_type_extension.dart
new file mode 100644
index 000000000..b1dd8ce19
--- /dev/null
+++ b/lib/model/extensions/enums/token_import_type_extension.dart
@@ -0,0 +1,20 @@
+import 'package:flutter/material.dart';
+
+import '../../../l10n/app_localizations.dart';
+import '../../enums/token_import_type.dart';
+
+extension TokenImportTypeExtension on TokenImportType {
+ IconData get icon => switch (this) {
+ const (TokenImportType.backupFile) => Icons.file_present,
+ const (TokenImportType.qrScan) => Icons.qr_code_scanner,
+ const (TokenImportType.qrFile) => Icons.qr_code_2,
+ const (TokenImportType.link) => Icons.link,
+ };
+
+ String buttonText(AppLocalizations localizations) => switch (this) {
+ const (TokenImportType.backupFile) => localizations.selectFile,
+ const (TokenImportType.qrScan) => localizations.scanQrCode,
+ const (TokenImportType.qrFile) => localizations.selectFile,
+ const (TokenImportType.link) => localizations.enterLink,
+ };
+}
diff --git a/lib/model/extensions/enums/token_origin_source_type.dart b/lib/model/extensions/enums/token_origin_source_type.dart
new file mode 100644
index 000000000..03220acfa
--- /dev/null
+++ b/lib/model/extensions/enums/token_origin_source_type.dart
@@ -0,0 +1,17 @@
+import '../../../mains/main_netknights.dart';
+import '../../enums/token_origin_source_type.dart';
+import '../../token_import/token_origin_data.dart';
+import '../../tokens/token.dart';
+
+extension TokenSourceTypeX on TokenOriginSourceType {
+ TokenOriginData toTokenOrigin({String data = '', String? appName, bool? isPrivacyIdeaToken, DateTime? createdAt}) => TokenOriginData(
+ source: this,
+ data: data,
+ appName: appName ?? PrivacyIDEAAuthenticator.currentCustomization?.appName,
+ isPrivacyIdeaToken: isPrivacyIdeaToken,
+ createdAt: createdAt ?? DateTime.now(),
+ );
+
+ T addOriginToToken({required T token, required String data, required bool? isPrivacyIdeaToken, String? appName, DateTime? createdAt}) =>
+ token.copyWith(origin: toTokenOrigin(data: data, appName: appName, isPrivacyIdeaToken: isPrivacyIdeaToken, createdAt: createdAt)) as T;
+}
diff --git a/lib/model/extensions/int_extension.dart b/lib/model/extensions/int_extension.dart
new file mode 100644
index 000000000..2dcace0cd
--- /dev/null
+++ b/lib/model/extensions/int_extension.dart
@@ -0,0 +1,28 @@
+import 'dart:math' as math;
+import 'dart:typed_data';
+
+extension IntExtension on int {
+ static const int maxInteger = 0x7FFFFFFFFFFFFFFF;
+ static const int minInteger = -0x8000000000000000;
+ Uint8List get bytes {
+ int long = this;
+ final byteArray = Uint8List(8);
+
+ for (var index = byteArray.length - 1; index >= 0; index--) {
+ final byte = long & 0xff;
+ byteArray[index] = byte;
+ long = (long - byte) ~/ 256;
+ }
+ return byteArray;
+ }
+
+ Iterable get digits sync* {
+ var number = this;
+ do {
+ yield number.remainder(10);
+ number ~/= 10;
+ } while (number != 0);
+ }
+
+ num pow(num exponent) => math.pow(this, exponent);
+}
diff --git a/lib/model/extensions/sortable_list.dart b/lib/model/extensions/sortable_list.dart
new file mode 100644
index 000000000..1c32c896b
--- /dev/null
+++ b/lib/model/extensions/sortable_list.dart
@@ -0,0 +1,85 @@
+import '../mixins/sortable_mixin.dart';
+
+extension SortableList on List {
+ List get sorted {
+ var list = List.from(this);
+ list.sort((a, b) => a.compareTo(b));
+ print('-----------------------------------');
+ list.forEach((element) {
+ print('sorted: ${element.runtimeType} Sortindex: ${element.sortIndex}');
+ });
+ print('-----------------------------------');
+ return list;
+ }
+
+ List fillNullIndices() {
+ var list = List.from(this);
+ var highestIndex = fold(0, (previousValue, element) {
+ if (element.sortIndex == null) return previousValue;
+ if (previousValue > element.sortIndex!) return previousValue;
+ return element.sortIndex!;
+ });
+ for (var i = 0; i < list.length; i++) {
+ if (list[i].sortIndex == null) {
+ highestIndex++;
+ list[i] = list[i].copyWith(sortIndex: highestIndex) as T;
+ }
+ }
+ print('-----------------------------------');
+ list.forEach((element) {
+ print('fillNullIndices: ${element.runtimeType} Sortindex: ${element.sortIndex}');
+ });
+ print('-----------------------------------');
+ return list;
+ }
+
+ /// Moves the [movedItem] to the position after [moveAfter] or before [moveBefore].
+ /// If both [moveAfter] and [moveBefore] are null, the [movedItem] will be moved to the end of the list.
+ /// If both is set, [moveBefore] will be prioritized.
+ List moveBetween({T? moveAfter, required T movedItem, T? moveBefore}) {
+ var list = List.from(this).sorted.withCurrentSortIndexSet();
+ final success = list.remove(movedItem);
+ if (!success) return list;
+ final newIndex = moveBefore != null
+ ? list.indexOf(moveBefore)
+ : moveAfter != null && list.contains(moveAfter)
+ ? list.indexOf(moveAfter) + 1
+ : list.length;
+ list.insert(newIndex, movedItem);
+ list = list.withCurrentSortIndexSet();
+ print('-----------------------------------');
+ list.forEach((element) {
+ print('moveBetween: ${element.runtimeType} Sortindex: ${element.sortIndex}');
+ });
+ print('-----------------------------------');
+ return list;
+ }
+
+ List moveAllBetween({T? moveAfter, required List movedItems, T? moveBefore}) {
+ var list = List.from(this).sorted.withCurrentSortIndexSet();
+ List removedItems = [];
+ for (final movedItem in movedItems) {
+ final success = list.remove(movedItem);
+ if (success) removedItems.add(movedItem);
+ }
+ if (removedItems.isEmpty) return list;
+ final newIndex = moveBefore != null
+ ? list.indexOf(moveBefore)
+ : moveAfter != null && list.contains(moveAfter)
+ ? list.indexOf(moveAfter) + 1
+ : list.length;
+ list.insertAll(newIndex, removedItems);
+ list = list.withCurrentSortIndexSet();
+ return list;
+ }
+
+ List withCurrentSortIndexSet() {
+ final list = List.from(this);
+ for (var i = 0; i < list.length; i++) {
+ if (list[i].sortIndex != i) {
+ list[i] = list[i].copyWith(sortIndex: i) as T;
+ }
+ }
+ return list;
+ }
+}
diff --git a/lib/model/mixins/sortable_mixin.dart b/lib/model/mixins/sortable_mixin.dart
index 9081babf4..5274c67f0 100644
--- a/lib/model/mixins/sortable_mixin.dart
+++ b/lib/model/mixins/sortable_mixin.dart
@@ -1,8 +1,9 @@
mixin SortableMixin {
int? get sortIndex;
-
SortableMixin copyWith({int? sortIndex});
+ /// Compares the sortIndex of two SortableMixin objects.
+ /// Null values are considered to be the highest index.
int compareTo(SortableMixin other) {
if (sortIndex == null) {
if (other.sortIndex == null) return 0;
diff --git a/lib/model/processor_result.dart b/lib/model/processor_result.dart
new file mode 100644
index 000000000..ffe5ca295
--- /dev/null
+++ b/lib/model/processor_result.dart
@@ -0,0 +1,25 @@
+abstract class ProcessorResult {
+ const ProcessorResult();
+ factory ProcessorResult.success(T data) => ProcessorResultSuccess(data);
+ factory ProcessorResult.failed(String errorMessage) => ProcessorResultFailed(errorMessage);
+ ProcessorResultSuccess? get asSuccess => this is ProcessorResultSuccess ? this as ProcessorResultSuccess : null;
+ ProcessorResultFailed? get asFailed => this is ProcessorResultFailed ? this as ProcessorResultFailed : null;
+}
+
+class ProcessorResultSuccess extends ProcessorResult {
+ final T resultData;
+ const ProcessorResultSuccess(this.resultData);
+
+ @override
+ String toString() {
+ return 'ProcessorResultSuccess(data: $resultData)';
+ }
+}
+
+class ProcessorResultFailed extends ProcessorResult {
+ final String message;
+ const ProcessorResultFailed(this.message);
+
+ @override
+ String toString() => '$runtimeType(message: $message)';
+}
diff --git a/lib/model/push_request.dart b/lib/model/push_request.dart
index cf361e3e5..6c7fa0dee 100644
--- a/lib/model/push_request.dart
+++ b/lib/model/push_request.dart
@@ -1,7 +1,14 @@
+import 'dart:convert';
+
+import 'package:base32/base32.dart';
import 'package:json_annotation/json_annotation.dart';
+import 'package:pi_authenticator_legacy/pi_authenticator_legacy.dart';
import '../utils/identifiers.dart';
import '../utils/logger.dart';
+import '../utils/riverpod_providers.dart';
+import '../utils/rsa_utils.dart';
+import 'tokens/push_token.dart';
part 'push_request.g.dart';
@@ -26,11 +33,10 @@ class PushRequest {
required this.sslVerify,
required this.id,
required this.expirationDate,
- String? serial,
- String? signature,
+ this.serial = '',
+ this.signature = '',
this.accepted,
- }) : serial = serial ?? '',
- signature = signature ?? '';
+ });
PushRequest copyWith({
String? title,
@@ -59,10 +65,10 @@ class PushRequest {
}
@override
- bool operator ==(Object other) => identical(this, other) || other is PushRequest && runtimeType == other.runtimeType && id == other.id;
+ bool operator ==(Object other) => other is PushRequest && runtimeType == other.runtimeType && id == other.id;
@override
- int get hashCode => id.hashCode;
+ int get hashCode => Object.hash(runtimeType, id);
@override
String toString() {
@@ -122,4 +128,34 @@ class PushRequest {
throw ArgumentError('Push request signature is ${data[PUSH_REQUEST_SIGNATURE].runtimeType}. Expected String.');
}
}
+
+ Future verifySignature(PushToken token, {LegacyUtils legacyUtils = const LegacyUtils(), RsaUtils rsaUtils = const RsaUtils()}) async {
+ Logger.info('Adding push request to token', name: 'push_request_notifier.dart#newRequest');
+ String signedData = '$nonce|'
+ '$uri|'
+ '$serial|'
+ '$question|'
+ '$title|'
+ '${sslVerify ? '1' : '0'}';
+
+ // Re-add url and sslverify to android legacy tokens:
+ if (token.url == null) {
+ globalRef?.read(tokenProvider.notifier).updateToken(token, (p0) => p0.copyWith(url: uri, sslVerify: sslVerify));
+ }
+
+ bool isVerified = token.privateTokenKey == null
+ ? await legacyUtils.verify(token.serial, signedData, signature)
+ : rsaUtils.verifyRSASignature(token.rsaPublicServerKey!, utf8.encode(signedData), base32.decode(signature));
+
+ if (!isVerified) {
+ Logger.warning(
+ 'Validating incoming message failed.',
+ name: 'token_notifier.dart#addPushRequestToToken',
+ error: 'Signature does not match signed data.',
+ );
+ return false;
+ }
+ Logger.info('Validating incoming message was successful.', name: 'token_notifier.dart#addPushRequestToToken');
+ return true;
+ }
}
diff --git a/lib/model/push_request.g.dart b/lib/model/push_request.g.dart
index 0ba01979b..a9ecce588 100644
--- a/lib/model/push_request.g.dart
+++ b/lib/model/push_request.g.dart
@@ -14,8 +14,8 @@ PushRequest _$PushRequestFromJson(Map json) => PushRequest(
sslVerify: json['sslVerify'] as bool,
id: json['id'] as int,
expirationDate: DateTime.parse(json['expirationDate'] as String),
- serial: json['serial'] as String?,
- signature: json['signature'] as String?,
+ serial: json['serial'] as String? ?? '',
+ signature: json['signature'] as String? ?? '',
accepted: json['accepted'] as bool?,
);
diff --git a/lib/model/push_request_queue.dart b/lib/model/push_request_queue.dart
deleted file mode 100644
index 95e92452f..000000000
--- a/lib/model/push_request_queue.dart
+++ /dev/null
@@ -1,80 +0,0 @@
-import 'package:collection/collection.dart';
-import 'package:json_annotation/json_annotation.dart';
-
-import 'push_request.dart';
-
-part 'push_request_queue.g.dart';
-
-@JsonSerializable()
-class PushRequestQueue {
- PushRequestQueue();
-
- List? _list;
-
- // The get and set methods are needed for serialization.
- List get list {
- _list ??= [];
- return _list!;
- }
-
- set list(List l) {
- if (_list != null) {
- throw ArgumentError('Initializing [list] in [PushRequestQueue] is only allowed once.');
- }
-
- _list = l;
- }
-
- int get length => list.length;
-
- void forEach(void Function(PushRequest request) f) => list.forEach((f));
-
- void removeWhere(bool Function(PushRequest request) f) => list.removeWhere(f);
-
- Iterable where(bool Function(PushRequest request) f) => list.where(f);
-
- bool any(bool Function(PushRequest element) f) => list.any(f);
-
- void remove(PushRequest request) {
- final prToRemove = list.firstWhereOrNull((element) => element.id == request.id);
- if (prToRemove == null) return;
- list.remove(prToRemove);
- }
-
- bool get isEmpty => list.isEmpty;
-
- bool get isNotEmpty => list.isNotEmpty;
-
- bool contains(PushRequest r) => list.contains(r);
-
- void add(PushRequest pushRequest) => list.add(pushRequest);
-
- PushRequest? peek() => list.isNotEmpty ? list.first : null;
-
- PushRequest? tryPop() => list.isNotEmpty ? list.removeAt(0) : null;
-
- @override
- String toString() {
- return 'PushRequestQueue{_list: $list}';
- }
-
- @override
- bool operator ==(Object other) => identical(this, other) || other is PushRequestQueue && runtimeType == other.runtimeType && _listsAreEqual(list, other.list);
-
- bool _listsAreEqual(List l1, List l2) {
- if (l1.length != l2.length) return false;
-
- for (int i = 0; i < l1.length - 1; i++) {
- if (l1[i] != l2[i]) return false;
- }
-
- return true;
- }
-
- @override
- int get hashCode => list.hashCode;
-
- factory PushRequestQueue.fromJson(Map json) => _$PushRequestQueueFromJson(json);
-
- Map toJson() => _$PushRequestQueueToJson(this);
-}
diff --git a/lib/model/push_request_queue.g.dart b/lib/model/push_request_queue.g.dart
deleted file mode 100644
index 0285d802f..000000000
--- a/lib/model/push_request_queue.g.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-part of 'push_request_queue.dart';
-
-// **************************************************************************
-// JsonSerializableGenerator
-// **************************************************************************
-
-PushRequestQueue _$PushRequestQueueFromJson(Map json) =>
- PushRequestQueue()
- ..list = (json['list'] as List)
- .map((e) => PushRequest.fromJson(e as Map))
- .toList();
-
-Map _$PushRequestQueueToJson(PushRequestQueue instance) =>
- {
- 'list': instance.list,
- };
diff --git a/lib/model/serializable_RSA_private_key.dart b/lib/model/serializable_RSA_private_key.dart
deleted file mode 100644
index a83f338d1..000000000
--- a/lib/model/serializable_RSA_private_key.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ignore_for_file: file_names
-
-import 'package:json_annotation/json_annotation.dart';
-import 'package:pointycastle/asymmetric/api.dart';
-
-part 'serializable_RSA_private_key.g.dart';
-
-@JsonSerializable()
-class SerializableRSAPrivateKey extends RSAPrivateKey {
- SerializableRSAPrivateKey(super.modulus, super.exponent, BigInt super.p, BigInt super.q);
-
- factory SerializableRSAPrivateKey.fromJson(Map json) => _$SerializableRSAPrivateKeyFromJson(json);
-
- Map toJson() => _$SerializableRSAPrivateKeyToJson(this);
-}
diff --git a/lib/model/serializable_RSA_private_key.g.dart b/lib/model/serializable_RSA_private_key.g.dart
deleted file mode 100644
index 31ac2fb60..000000000
--- a/lib/model/serializable_RSA_private_key.g.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-part of 'serializable_RSA_private_key.dart';
-
-// **************************************************************************
-// JsonSerializableGenerator
-// **************************************************************************
-
-SerializableRSAPrivateKey _$SerializableRSAPrivateKeyFromJson(
- Map json) =>
- SerializableRSAPrivateKey(
- BigInt.parse(json['modulus'] as String),
- BigInt.parse(json['exponent'] as String),
- BigInt.parse(json['p'] as String),
- BigInt.parse(json['q'] as String),
- );
-
-Map _$SerializableRSAPrivateKeyToJson(
- SerializableRSAPrivateKey instance) =>
- {
- 'modulus': instance.modulus?.toString(),
- 'exponent': instance.exponent?.toString(),
- 'p': instance.p?.toString(),
- 'q': instance.q?.toString(),
- };
diff --git a/lib/model/serializable_RSA_public_key.dart b/lib/model/serializable_RSA_public_key.dart
deleted file mode 100644
index 3096d6a6a..000000000
--- a/lib/model/serializable_RSA_public_key.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// ignore_for_file: file_names
-
-import 'package:json_annotation/json_annotation.dart';
-import 'package:pointycastle/asymmetric/api.dart';
-
-part 'serializable_RSA_public_key.g.dart';
-
-@JsonSerializable()
-class SerializableRSAPublicKey extends RSAPublicKey {
- SerializableRSAPublicKey(super.modulus, super.exponent);
-
- factory SerializableRSAPublicKey.fromJson(Map json) => _$SerializableRSAPublicKeyFromJson(json);
-
- Map toJson() => _$SerializableRSAPublicKeyToJson(this);
-}
diff --git a/lib/model/serializable_RSA_public_key.g.dart b/lib/model/serializable_RSA_public_key.g.dart
deleted file mode 100644
index 6350252c0..000000000
--- a/lib/model/serializable_RSA_public_key.g.dart
+++ /dev/null
@@ -1,21 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-part of 'serializable_RSA_public_key.dart';
-
-// **************************************************************************
-// JsonSerializableGenerator
-// **************************************************************************
-
-SerializableRSAPublicKey _$SerializableRSAPublicKeyFromJson(
- Map json) =>
- SerializableRSAPublicKey(
- BigInt.parse(json['modulus'] as String),
- BigInt.parse(json['exponent'] as String),
- );
-
-Map _$SerializableRSAPublicKeyToJson(
- SerializableRSAPublicKey instance) =>
- {
- 'modulus': instance.modulus?.toString(),
- 'exponent': instance.exponent?.toString(),
- };
diff --git a/lib/model/states/introduction_state.dart b/lib/model/states/introduction_state.dart
index 794295efb..016254314 100644
--- a/lib/model/states/introduction_state.dart
+++ b/lib/model/states/introduction_state.dart
@@ -2,6 +2,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:json_annotation/json_annotation.dart';
import '../enums/introduction.dart';
+import '../extensions/enums/introduction_extension.dart';
part 'introduction_state.g.dart';
diff --git a/lib/model/states/introduction_state.g.dart b/lib/model/states/introduction_state.g.dart
index 433334f91..b1095d878 100644
--- a/lib/model/states/introduction_state.g.dart
+++ b/lib/model/states/introduction_state.g.dart
@@ -24,7 +24,7 @@ Map _$IntroductionStateToJson(IntroductionState instance) =>
const _$IntroductionEnumMap = {
Introduction.introductionScreen: 'introductionScreen',
Introduction.scanQrCode: 'scanQrCode',
- Introduction.addTokenManually: 'addManually',
+ Introduction.addManually: 'addManually',
Introduction.tokenSwipe: 'tokenSwipe',
Introduction.editToken: 'editToken',
Introduction.lockToken: 'lockToken',
diff --git a/lib/model/states/push_request_state.dart b/lib/model/states/push_request_state.dart
new file mode 100644
index 000000000..51fa8b8b4
--- /dev/null
+++ b/lib/model/states/push_request_state.dart
@@ -0,0 +1,86 @@
+import 'package:flutter/foundation.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+import '../../utils/custom_int_buffer.dart';
+import '../push_request.dart';
+
+part 'push_request_state.g.dart';
+
+@JsonSerializable()
+class PushRequestState {
+ final List pushRequests;
+ final CustomIntBuffer knownPushRequests;
+ const PushRequestState({required this.pushRequests, required this.knownPushRequests});
+
+ bool knowsRequestId(int id) => knownPushRequests.contains(id);
+ bool knowsRequest(PushRequest pushRequest) => knowsRequestId(pushRequest.id);
+
+ /// Adds the given push request to a new state and returns it.
+ PushRequestState withRequest(PushRequest pushRequest) => PushRequestState(
+ pushRequests: pushRequests.toList()..add(pushRequest),
+ knownPushRequests: knownPushRequests.put(pushRequest.id),
+ );
+
+ PushRequestState withoutRequest(PushRequest pushRequest) => PushRequestState(
+ pushRequests: pushRequests.toList()..remove(pushRequest),
+ knownPushRequests: knownPushRequests.copyWith(),
+ );
+
+ PushRequestState addOrReplace(PushRequest pushRequest) {
+ final requests = pushRequests.toList();
+ final knowenIds = knownPushRequests.toList();
+ if (requests.contains(pushRequest)) {
+ return PushRequestState(
+ pushRequests: requests
+ ..remove(pushRequest)
+ ..add(pushRequest),
+ knownPushRequests: knownPushRequests,
+ );
+ }
+ knowenIds.add(pushRequest.id);
+ return PushRequestState(
+ pushRequests: requests..add(pushRequest),
+ knownPushRequests: CustomIntBuffer(list: knowenIds),
+ );
+ }
+
+ (PushRequestState, bool) replaceRequest(PushRequest pushRequest) {
+ final newRequests = pushRequests.toList();
+ final index = newRequests.indexWhere((element) => element.id == pushRequest.id);
+ if (index == -1) {
+ return (this, false);
+ }
+ newRequests[index] = pushRequest;
+ return (PushRequestState(pushRequests: newRequests, knownPushRequests: knownPushRequests), true);
+ }
+
+ PushRequest? currentOf(PushRequest pushRequest) => pushRequests.firstWhere((element) => element.id == pushRequest.id);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+
+ return other is PushRequestState && listEquals(other.pushRequests, pushRequests) && other.knownPushRequests == knownPushRequests;
+ }
+
+ @override
+ int get hashCode => pushRequests.hashCode * 31 + knownPushRequests.hashCode;
+
+ @override
+ String toString() => 'PushRequestState(pushRequests: $pushRequests, knownPushRequests: $knownPushRequests)';
+
+ /*
+ //////////////////////////////////////////////////
+ /////////////// Json Serialization ///////////////
+ //////////////////////////////////////////////////
+ */
+ Map toJson() => {
+ 'pushRequests': pushRequests.map((e) => e.toJson()).toList(),
+ 'knownPushRequests': knownPushRequests.toJson(),
+ };
+
+ factory PushRequestState.fromJson(Map json) => PushRequestState(
+ pushRequests: (json['pushRequests'] as List).map((e) => PushRequest.fromJson(e)).toList(),
+ knownPushRequests: CustomIntBuffer.fromJson(json['knownPushRequests']),
+ );
+}
diff --git a/lib/model/states/push_request_state.g.dart b/lib/model/states/push_request_state.g.dart
new file mode 100644
index 000000000..33064ac83
--- /dev/null
+++ b/lib/model/states/push_request_state.g.dart
@@ -0,0 +1,22 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'push_request_state.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+PushRequestState _$PushRequestStateFromJson(Map json) =>
+ PushRequestState(
+ pushRequests: (json['pushRequests'] as List)
+ .map((e) => PushRequest.fromJson(e as Map))
+ .toList(),
+ knownPushRequests: CustomIntBuffer.fromJson(
+ json['knownPushRequests'] as Map),
+ );
+
+Map _$PushRequestStateToJson(PushRequestState instance) =>
+ {
+ 'pushRequests': instance.pushRequests,
+ 'knownPushRequests': instance.knownPushRequests,
+ };
diff --git a/lib/model/states/settings_state.dart b/lib/model/states/settings_state.dart
index 5fadc4829..1d363e4a4 100644
--- a/lib/model/states/settings_state.dart
+++ b/lib/model/states/settings_state.dart
@@ -2,10 +2,10 @@ import 'dart:io';
import 'dart:ui';
import 'package:flutter/foundation.dart';
-import '../../utils/version.dart';
import '../../l10n/app_localizations.dart';
import '../../utils/identifiers.dart';
+import '../version.dart';
/// This class contains all device specific settings. E.g., the language used, whether to show the guide on start, etc.
class SettingsState {
diff --git a/lib/model/states/token_folder_state.dart b/lib/model/states/token_folder_state.dart
index c5010e532..f87626322 100644
--- a/lib/model/states/token_folder_state.dart
+++ b/lib/model/states/token_folder_state.dart
@@ -11,15 +11,19 @@ class TokenFolderState {
const TokenFolderState({required this.folders});
- TokenFolderState withFolder(String name) {
+ /// Add a new folder with the given name
+ /// Returns a new TokenFolderState with the new folder
+ /// The original List is not modified
+ TokenFolderState addNewFolder(String name) {
final newFolders = List.from(folders);
newFolders.add(TokenFolder(label: name, folderId: newFolderId));
return TokenFolderState(folders: newFolders);
}
- // replace all folders where the folderid is the same
- // if the folderid is none, add it to the list
- TokenFolderState withUpdated(List folders) {
+ /// Add or replace the folders with the same folderId
+ /// Returns a new TokenFolderState with the new folders
+ /// The original List is not modified
+ TokenFolderState addOrReplaceFolders(List folders) {
final newFolders = List.from(this.folders);
for (var newFolder in folders) {
final index = newFolders.indexWhere((oldFolder) => oldFolder.folderId == newFolder.folderId);
@@ -30,13 +34,28 @@ class TokenFolderState {
return TokenFolderState(folders: newFolders);
}
- TokenFolderState withoutFolder(TokenFolder folder) {
+ TokenFolderState addOrReplaceFolder(TokenFolder newFolder) {
+ final newFolders = List.from(folders);
+ final index = newFolders.indexWhere((element) => element.folderId == newFolder.folderId);
+ if (index != -1) {
+ newFolders[index] = newFolder;
+ }
+ return TokenFolderState(folders: newFolders);
+ }
+
+ /// Remove the folder with the same folderId
+ /// Returns a new TokenFolderState without the folder
+ /// The original List is not modified
+ TokenFolderState removeFolder(TokenFolder folder) {
final newFolders = List.from(folders);
newFolders.removeWhere((element) => element.folderId == folder.folderId);
return TokenFolderState(folders: newFolders);
}
- TokenFolderState withoutFolders(List folders) {
+ /// Remove the folders with the same folderId
+ /// Returns a new TokenFolderState without the folders
+ /// The original List is not modified
+ TokenFolderState removeFolders(List folders) {
final newFolders = List.from(this.folders);
newFolders.removeWhere((element) => folders.any((folder) => folder.folderId == element.folderId));
return TokenFolderState(folders: newFolders);
@@ -54,5 +73,9 @@ class TokenFolderState {
get newFolderId => folders.fold(0, (previousValue, element) => max(previousValue, element.folderId)) + 1;
- TokenFolder? getFolderById(int? id) => id == null ? null : folders.firstWhereOrNull((element) => element.folderId == id);
+ /// Get the folder by the given id, or null if the folder does not exist
+ TokenFolder? currentById(int? id) => id == null ? null : folders.firstWhereOrNull((element) => element.folderId == id);
+
+ /// Returns the current folder of the given folder, or null if the folder does not exist
+ TokenFolder? currentOf(TokenFolder folder) => folders.firstWhereOrNull((element) => element.folderId == folder.folderId);
}
diff --git a/lib/model/states/token_state.dart b/lib/model/states/token_state.dart
index 2295f7a74..9f3d2199f 100644
--- a/lib/model/states/token_state.dart
+++ b/lib/model/states/token_state.dart
@@ -23,35 +23,26 @@ class TokenState {
List get pushTokensToRollOut =>
pushTokens.where((element) => !element.isRolledOut && element.rolloutState == PushTokenRollOutState.rolloutNotStarted).toList();
- TokenState({List tokens = const [], List? lastlyUpdatedTokens})
+ TokenState({required List tokens, List? lastlyUpdatedTokens})
: tokens = List.from(tokens),
- lastlyUpdatedTokens = lastlyUpdatedTokens ?? List.from(tokens) {
- _sort(this.tokens);
- }
- TokenState repaceList({List? tokens}) => TokenState(tokens: tokens ?? this.tokens);
+ lastlyUpdatedTokens = List.from(lastlyUpdatedTokens ?? tokens);
- Map tokensWithSameSectet(List tokens) {
- final tokensWithSameSectet = {};
- final stateTokens = this.tokens;
- List otpTokens = tokens.whereType().toList();
- Map stateOtpTokens = {for (var e in stateTokens.whereType()) (e).secret: e};
- List pushTokens = tokens.whereType().toList();
- Map<(String?, String?, String?), PushToken> statePushTokens = {
- for (var e in stateTokens.whereType()) (e.publicServerKey, e.privateTokenKey, e.publicTokenKey): e
- };
-
- for (var pushToken in pushTokens) {
- tokensWithSameSectet[pushToken] = statePushTokens[(pushToken.publicServerKey, pushToken.privateTokenKey, pushToken.publicTokenKey)];
- }
- for (var otpToken in otpTokens) {
- tokensWithSameSectet[otpToken] = stateOtpTokens[otpToken.secret];
- }
+ List get nonPiTokens => tokens.where((token) => token.isPrivacyIdeaToken == false).toList();
- return tokensWithSameSectet;
- }
+ PushToken? getTokenBySerial(String serial) => pushTokens.firstWhereOrNull((element) => element.serial == serial);
- static void _sort(List tokens) {
- tokens.sort((a, b) => (a.sortIndex ?? double.infinity).compareTo(b.sortIndex ?? double.infinity));
+ /// Maps the given tokens to the tokens that are already in the state
+ /// It ignores the id that is usually used to identify the token
+ /// Instead it uses the non-changeable values of the token to identify it
+ /// Like the secret and hash algorithm for OTP tokens, or the serial and public server key for push tokens
+ Map getSameTokens(List tokens) {
+ final sameTokensMap = {};
+ final stateTokens = this.tokens;
+
+ for (var token in tokens) {
+ sameTokensMap[token] = stateTokens.firstWhereOrNull((element) => element.isSameTokenAs(token));
+ }
+ return sameTokensMap;
}
T? currentOf(T token) => tokens.firstWhereOrNull((element) => element.id == token.id) as T?;
@@ -80,7 +71,7 @@ class TokenState {
TokenState withoutTokens(List tokens) {
final newTokens = List.from(this.tokens);
newTokens.removeWhere((element) => tokens.any((token) => token.id == element.id));
- return TokenState(tokens: newTokens, lastlyUpdatedTokens: tokens);
+ return TokenState(tokens: newTokens, lastlyUpdatedTokens: const []);
}
// Add a token if it does not exist yet
@@ -98,66 +89,71 @@ class TokenState {
// Replace the token if it does exist
// Do nothing if it does not exist
- TokenState replaceToken(Token token) {
- final newTokens = List.from(tokens);
+ (TokenState, bool) replaceToken(Token token) {
+ final newTokens = tokens.toList();
final index = newTokens.indexWhere((element) => element.id == token.id);
if (index == -1) {
Logger.warning('Tried to replace a token that does not exist.', name: 'token_state.dart#replaceToken');
- return this;
+ return (this, false);
}
newTokens[index] = token;
- return TokenState(tokens: newTokens, lastlyUpdatedTokens: [token]);
+ return (TokenState(tokens: newTokens, lastlyUpdatedTokens: [token]), true);
}
// replace all tokens where the id is the same
// if the id is none, add it to the list
- TokenState addOrReplaceTokens(List tokens) {
+ TokenState addOrReplaceTokens(List tokens) {
final newTokens = List.from(this.tokens);
+ final updatedTokens = [];
for (var token in tokens) {
final index = newTokens.indexWhere((element) => element.id == token.id);
if (index == -1) {
newTokens.add(token);
+ updatedTokens.add(token);
continue;
}
newTokens[index] = token;
+ updatedTokens.add(token);
}
- return TokenState(tokens: newTokens, lastlyUpdatedTokens: tokens);
+ return TokenState(tokens: newTokens, lastlyUpdatedTokens: updatedTokens);
}
// Replace the tokens if it does exist
// Do nothing if it does not exist
- TokenState replaceTokens(List tokens) {
+ (TokenState, List) replaceTokens(List tokens) {
final newTokens = List.from(this.tokens);
- final lastlyUpdatedTokens = [];
+ final updatedTokens = [];
+ final failedToReplace = [];
for (var token in tokens) {
final index = newTokens.indexWhere((element) => element.id == token.id);
if (index == -1) {
Logger.warning('Tried to replace a token that does not exist.', name: 'token_state.dart#replaceToken');
+ failedToReplace.add(token);
continue;
}
newTokens[index] = token;
- lastlyUpdatedTokens.add(token);
}
- return TokenState(tokens: newTokens, lastlyUpdatedTokens: lastlyUpdatedTokens);
+ return (TokenState(tokens: newTokens, lastlyUpdatedTokens: updatedTokens), failedToReplace);
}
- List tokensInFolder(TokenFolder folder, {List? only, List? exclude}) => tokens.where((token) {
- if (token.folderId != folder.folderId) {
- return false;
- }
- if (exclude != null && exclude.contains(token.runtimeType)) return false;
- if (only != null && !only.contains(token.runtimeType)) return false;
+ List tokensInFolder(TokenFolder folder, {List only = const [], List exclude = const []}) =>
+ tokens.inFolder(folder, only: only, exclude: exclude);
+
+ List tokensWithoutFolder({List only = const [], List exclude = const []}) => tokens.withoutFolder(only: only, exclude: exclude);
+}
+
+extension TokenListExtension on List {
+ List inFolder(TokenFolder folder, {List only = const [], List exclude = const []}) => where((token) {
+ if (token.folderId != folder.folderId) return false;
+ if (exclude.contains(token.runtimeType)) return false;
+ if (only.isNotEmpty && !only.contains(token.runtimeType)) return false;
return true;
}).toList();
- List tokensWithoutFolder({List? only, List? exclude}) => tokens.where((token) {
- if (token.folderId != null) {
- return false;
- }
- if (exclude != null && exclude.contains(token.runtimeType)) return false;
- if (only != null && !only.contains(token.runtimeType)) return false;
+ List withoutFolder({List only = const [], List exclude = const []}) => where((token) {
+ if (token.folderId != null) return false;
+ if (exclude.contains(token.runtimeType)) return false;
+ if (only.isNotEmpty && !only.contains(token.runtimeType)) return false;
return true;
}).toList();
-
- PushToken? tokenWithPushRequest() => tokens.whereType().firstWhereOrNull((token) => token.pushRequests.isNotEmpty);
}
diff --git a/lib/model/token_folder.dart b/lib/model/token_folder.dart
index 745240c1a..12c48674f 100644
--- a/lib/model/token_folder.dart
+++ b/lib/model/token_folder.dart
@@ -14,7 +14,7 @@ class TokenFolder with SortableMixin {
final bool isLocked;
@override
final int? sortIndex;
-
+ @override
const TokenFolder({
required this.label,
required this.folderId,
diff --git a/lib/model/token_import/token_import_origin.dart b/lib/model/token_import/token_import_origin.dart
new file mode 100644
index 000000000..78f931819
--- /dev/null
+++ b/lib/model/token_import/token_import_origin.dart
@@ -0,0 +1,13 @@
+import 'token_import_source.dart';
+
+class TokenImportOrigin {
+ final String appName;
+ final String? iconPath;
+ final List importSources;
+
+ const TokenImportOrigin({
+ required this.appName,
+ required this.importSources,
+ this.iconPath,
+ });
+}
diff --git a/lib/model/token_import/token_import_source.dart b/lib/model/token_import/token_import_source.dart
new file mode 100644
index 000000000..9e15f1b71
--- /dev/null
+++ b/lib/model/token_import/token_import_source.dart
@@ -0,0 +1,11 @@
+import '../../l10n/app_localizations.dart';
+import '../../processors/mixins/token_import_processor.dart';
+import '../enums/token_import_type.dart';
+
+class TokenImportSource {
+ final TokenImportType type;
+ final TokenImportProcessor processor;
+ final String Function(AppLocalizations localizations) importHint;
+
+ const TokenImportSource({required this.processor, required this.type, required this.importHint});
+}
diff --git a/lib/model/token_import/token_origin_data.dart b/lib/model/token_import/token_origin_data.dart
new file mode 100644
index 000000000..8f02a54fa
--- /dev/null
+++ b/lib/model/token_import/token_origin_data.dart
@@ -0,0 +1,75 @@
+import 'package:json_annotation/json_annotation.dart';
+
+import '../enums/token_origin_source_type.dart';
+import '../version.dart';
+
+part 'token_origin_data.g.dart';
+
+@JsonSerializable()
+class TokenOriginData {
+ final TokenOriginSourceType source;
+ final String? appName;
+ final String data;
+ final bool? isPrivacyIdeaToken;
+ final DateTime? createdAt;
+ final Version? piServerVersion;
+ const TokenOriginData._({
+ required this.source,
+ required this.data,
+ this.appName,
+ this.isPrivacyIdeaToken,
+ this.createdAt,
+ this.piServerVersion,
+ });
+
+ factory TokenOriginData({
+ required TokenOriginSourceType source,
+ required String data,
+ String? appName,
+ bool? isPrivacyIdeaToken,
+ DateTime? createdAt,
+ Version? piServerVersion,
+ }) =>
+ TokenOriginData._(
+ source: source,
+ appName: appName,
+ data: data,
+ isPrivacyIdeaToken: isPrivacyIdeaToken,
+ createdAt: createdAt ?? DateTime.now(),
+ piServerVersion: piServerVersion,
+ );
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+ return other is TokenOriginData && other.source == source && other.appName == appName && other.data == data;
+ }
+
+ TokenOriginData copyWith({
+ TokenOriginSourceType? source,
+ String? data,
+ String? appName,
+ bool? isPrivacyIdeaToken,
+ DateTime? createdAt,
+ Version? piServerVersion,
+ }) =>
+ TokenOriginData(
+ source: source ?? this.source,
+ appName: appName ?? this.appName,
+ data: data ?? this.data,
+ isPrivacyIdeaToken: isPrivacyIdeaToken ?? this.isPrivacyIdeaToken,
+ createdAt: createdAt ?? this.createdAt,
+ piServerVersion: piServerVersion ?? this.piServerVersion,
+ );
+
+ @override
+ int get hashCode => Object.hashAll([source, appName, data]);
+
+ // toString prints not data because it contains the secret
+ @override
+ String toString() => 'TokenOrigin{source: $source, app: $appName, isPrivacyIdeaToken: $isPrivacyIdeaToken, createdAt: $createdAt, data: $data';
+
+ factory TokenOriginData.fromJson(Map json) => _$TokenOriginDataFromJson(json);
+
+ Map toJson() => _$TokenOriginDataToJson(this);
+}
diff --git a/lib/model/token_origin.g.dart b/lib/model/token_import/token_origin_data.g.dart
similarity index 61%
rename from lib/model/token_origin.g.dart
rename to lib/model/token_import/token_origin_data.g.dart
index cfc4bfa32..07d913023 100644
--- a/lib/model/token_origin.g.dart
+++ b/lib/model/token_import/token_origin_data.g.dart
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
-part of 'token_origin.dart';
+part of 'token_origin_data.dart';
// **************************************************************************
// JsonSerializableGenerator
@@ -11,6 +11,13 @@ TokenOriginData _$TokenOriginDataFromJson(Map json) =>
source: $enumDecode(_$TokenOriginSourceTypeEnumMap, json['source']),
data: json['data'] as String,
appName: json['appName'] as String?,
+ isPrivacyIdeaToken: json['isPrivacyIdeaToken'] as bool?,
+ createdAt: json['createdAt'] == null
+ ? null
+ : DateTime.parse(json['createdAt'] as String),
+ piServerVersion: json['piServerVersion'] == null
+ ? null
+ : Version.fromJson(json['piServerVersion'] as Map),
);
Map _$TokenOriginDataToJson(TokenOriginData instance) =>
@@ -18,13 +25,18 @@ Map _$TokenOriginDataToJson(TokenOriginData instance) =>
'source': _$TokenOriginSourceTypeEnumMap[instance.source]!,
'appName': instance.appName,
'data': instance.data,
+ 'isPrivacyIdeaToken': instance.isPrivacyIdeaToken,
+ 'createdAt': instance.createdAt?.toIso8601String(),
+ 'piServerVersion': instance.piServerVersion,
};
const _$TokenOriginSourceTypeEnumMap = {
TokenOriginSourceType.backupFile: 'backupFile',
TokenOriginSourceType.qrScan: 'qrScan',
TokenOriginSourceType.qrFile: 'qrFile',
+ TokenOriginSourceType.qrScanImport: 'qrScanImport',
TokenOriginSourceType.link: 'link',
+ TokenOriginSourceType.linkImport: 'linkImport',
TokenOriginSourceType.manually: 'manually',
TokenOriginSourceType.unknown: 'unknown',
};
diff --git a/lib/model/token_import_origin.dart b/lib/model/token_import_origin.dart
deleted file mode 100644
index 9ae032bb5..000000000
--- a/lib/model/token_import_origin.dart
+++ /dev/null
@@ -1,82 +0,0 @@
-import 'package:flutter/material.dart';
-
-import '../l10n/app_localizations.dart';
-import '../processors/mixins/token_import_processor.dart';
-import '../processors/scheme_processors/token_import_scheme_processors/otp_auth_migration_processor.dart';
-import '../processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart';
-import '../processors/token_import_file_processor/aegis_import_file_processor.dart';
-import '../processors/token_import_file_processor/two_fas_import_file_processor.dart';
-import 'enums/token_import_type.dart';
-
-class TokenImportOrigin {
- final String appName;
- final String? iconPath;
- final List importEntitys;
-
- const TokenImportOrigin({
- required this.appName,
- required this.importEntitys,
- this.iconPath,
- });
-}
-
-class TokenImportEntity {
- final TokenImportType type;
- final TokenImportProcessor processor;
- final String Function(BuildContext context) importHint;
-
- const TokenImportEntity({required this.processor, required this.type, required this.importHint});
-}
-
-class TokenImportSourceList {
- static const _importSourceIconFolder = 'assets/images/import_sources/';
- static List appList = [
- TokenImportOrigin(
- appName: 'Google Authenticator',
- iconPath: '${_importSourceIconFolder}google_authenticator.png',
- importEntitys: [
- TokenImportEntity(
- processor: const OtpAuthMigrationProcessor(),
- type: TokenImportType.qrScan,
- importHint: (context) => AppLocalizations.of(context)!.importHintGoogleQrScan,
- ),
- TokenImportEntity(
- processor: const OtpAuthMigrationProcessor(),
- type: TokenImportType.qrFile,
- importHint: (context) => AppLocalizations.of(context)!.importHintGoogleQrFile,
- ),
- ],
- ),
- TokenImportOrigin(
- appName: 'Aegis Authenticator',
- iconPath: '${_importSourceIconFolder}aegis_authenticator.png',
- importEntitys: [
- TokenImportEntity(
- processor: const AegisImportFileProcessor(),
- type: TokenImportType.backupFile,
- importHint: (context) => AppLocalizations.of(context)!.importHintAegisBackupFile,
- ),
- TokenImportEntity(
- processor: const OtpAuthProcessor(),
- type: TokenImportType.qrScan,
- importHint: (context) => AppLocalizations.of(context)!.importHintAegisQrScan,
- ),
- TokenImportEntity(
- processor: const OtpAuthProcessor(),
- type: TokenImportType.link,
- importHint: (context) => AppLocalizations.of(context)!.importHintAegisLink,
- ),
- ],
- ),
- TokenImportOrigin(
- appName: '2FAS Authenticator',
- iconPath: '${_importSourceIconFolder}2fas.png',
- importEntitys: [
- TokenImportEntity(
- processor: const TwoFasFileImportProcessor(),
- type: TokenImportType.backupFile,
- importHint: (context) => AppLocalizations.of(context)!.importHint2FAS),
- ],
- ),
- ];
-}
diff --git a/lib/model/token_origin.dart b/lib/model/token_origin.dart
deleted file mode 100644
index 3d3038cdc..000000000
--- a/lib/model/token_origin.dart
+++ /dev/null
@@ -1,21 +0,0 @@
-import 'package:json_annotation/json_annotation.dart';
-
-import 'enums/token_origin_source_type.dart';
-
-part 'token_origin.g.dart';
-
-@JsonSerializable()
-class TokenOriginData {
- TokenOriginSourceType source;
- String? appName;
- String data;
- TokenOriginData({required this.source, required this.data, this.appName});
-
- // toString prints not data because it contains the secret
- @override
- String toString() => 'TokenOrigin{source: $source, app: $appName}';
-
- factory TokenOriginData.fromJson(Map json) => _$TokenOriginDataFromJson(json);
-
- Map toJson() => _$TokenOriginDataToJson(this);
-}
diff --git a/lib/model/tokens/day_password_token.dart b/lib/model/tokens/day_password_token.dart
index 219878dce..df5c5165a 100644
--- a/lib/model/tokens/day_password_token.dart
+++ b/lib/model/tokens/day_password_token.dart
@@ -1,17 +1,16 @@
import 'package:flutter/material.dart';
import 'package:json_annotation/json_annotation.dart';
-import 'package:otp/otp.dart' as otp_library;
import 'package:uuid/uuid.dart';
-import '../../utils/crypto_utils.dart';
+import '../../utils/errors.dart';
import '../../utils/identifiers.dart';
-import '../../utils/utils.dart';
import '../enums/algorithms.dart';
-import '../enums/day_passoword_token_view_mode.dart';
+import '../enums/day_password_token_view_mode.dart';
import '../enums/encodings.dart';
import '../enums/token_types.dart';
-import '../extensions/enum_extension.dart';
-import '../token_origin.dart';
+import '../extensions/enums/algorithms_extension.dart';
+import '../extensions/enums/encodings_extension.dart';
+import '../token_import/token_origin_data.dart';
import 'otp_token.dart';
import 'token.dart';
@@ -20,17 +19,12 @@ part 'day_password_token.g.dart';
@JsonSerializable()
@immutable
class DayPasswordToken extends OTPToken {
- static String get tokenType => TokenTypes.DAYPASSWORD.asString;
+ static String get tokenType => TokenTypes.DAYPASSWORD.name;
final DayPasswordTokenViewMode viewMode;
final Duration period;
- @override
- Duration get showDuration => const Duration(seconds: 30);
-
DayPasswordToken({
required Duration period,
- required super.label,
- required super.issuer,
required super.id,
required super.algorithm,
required super.digits,
@@ -44,14 +38,31 @@ class DayPasswordToken extends OTPToken {
super.isLocked,
super.isHidden,
super.origin,
+ super.label = '',
+ super.issuer = '',
}) : period = period.inSeconds > 0 ? period : const Duration(hours: 24),
- super(type: TokenTypes.DAYPASSWORD.asString);
+ super(type: TokenTypes.DAYPASSWORD.name);
@override
+ // Only the viewMode can be changed even if its the same token
bool sameValuesAs(Token other) {
- return super.sameValuesAs(other) && other is DayPasswordToken && other.period == period;
+ return super.sameValuesAs(other) && other is DayPasswordToken && other.viewMode == viewMode;
}
+ @override
+ // It is the same token the the period as to be the same
+ bool isSameTokenAs(Token other) {
+ return super.isSameTokenAs(other) && other is DayPasswordToken && other.period == period;
+ }
+
+ @override
+ bool operator ==(Object other) {
+ return super == other && other is DayPasswordToken && other.period == period && other.viewMode == viewMode;
+ }
+
+ @override
+ int get hashCode => Object.hashAll([super.hashCode, period, viewMode]);
+
@override
DayPasswordToken copyWith({
Duration? period,
@@ -63,10 +74,10 @@ class DayPasswordToken extends OTPToken {
int? digits,
String? secret,
String? tokenImage,
- int? sortIndex,
bool? pin,
bool? isLocked,
bool? isHidden,
+ int? sortIndex,
int? Function()? folderId,
TokenOriginData? origin,
}) =>
@@ -76,7 +87,7 @@ class DayPasswordToken extends OTPToken {
label: label ?? this.label,
issuer: issuer ?? this.issuer,
id: id ?? this.id,
- type: TokenTypes.DAYPASSWORD.asString,
+ type: TokenTypes.DAYPASSWORD.name,
algorithm: algorithm ?? this.algorithm,
digits: digits ?? this.digits,
secret: secret ?? this.secret,
@@ -85,17 +96,16 @@ class DayPasswordToken extends OTPToken {
pin: pin ?? this.pin,
isLocked: isLocked ?? this.isLocked,
isHidden: isHidden ?? this.isHidden,
- folderId: folderId != null ? folderId.call() : this.folderId,
+ folderId: folderId != null ? folderId() : this.folderId,
origin: origin ?? this.origin,
);
@override
- String get otpValue => otp_library.OTP.generateTOTPCodeString(
- secret,
- DateTime.now().millisecondsSinceEpoch,
+ String get otpValue => algorithm.generateTOTPCodeString(
+ secret: secret,
+ time: DateTime.now(),
length: digits,
- algorithm: algorithm.otpLibraryAlgorithm,
- interval: period.inSeconds,
+ interval: period,
isGoogle: true,
);
@@ -111,35 +121,56 @@ class DayPasswordToken extends OTPToken {
return DateTime.now().add(durationUntilNextOTP + const Duration(milliseconds: 1));
}
- factory DayPasswordToken.fromUriMap(Map uriMap) {
- if (uriMap[URI_SECRET] == null) throw ArgumentError('Secret is required');
- if (uriMap[URI_PERIOD] < 1) throw ArgumentError('Period must be greater than 0');
- if (uriMap[URI_DIGITS] < 1) throw ArgumentError('Digits must be greater than 0');
- DayPasswordToken dayPasswordToken;
- try {
- dayPasswordToken = DayPasswordToken(
- label: uriMap[URI_LABEL] ?? '',
- issuer: uriMap[URI_ISSUER] ?? '',
- id: const Uuid().v4(),
- algorithm: mapStringToAlgorithm(uriMap[URI_ALGORITHM] ?? 'SHA1'),
- digits: uriMap[URI_DIGITS] ?? 6,
- secret: encodeSecretAs(uriMap[URI_SECRET], Encodings.base32),
- period: Duration(seconds: uriMap[URI_PERIOD]),
- tokenImage: uriMap[URI_IMAGE],
- pin: uriMap[URI_PIN],
- isLocked: uriMap[URI_PIN],
+ /// Throws an Error if the uriMap is invalid
+ static void validateUriMap(Map uriMap) {
+ if (uriMap[URI_SECRET] == null) {
+ throw LocalizedArgumentError(
+ localizedMessage: ((localizations, value, name) => localizations.secretIsRequired),
+ unlocalizedMessage: 'Secret is required',
+ invalidValue: uriMap[URI_SECRET],
+ name: URI_SECRET,
+ );
+ }
+ if (uriMap[URI_PERIOD] != null && uriMap[URI_PERIOD] < 1) {
+ throw LocalizedArgumentError(
+ localizedMessage: (localizations, value, parameter) => localizations.invalidValueForParameter(value, parameter),
+ unlocalizedMessage: 'Period must be greater than 0',
+ invalidValue: uriMap[URI_PERIOD],
+ name: URI_PERIOD,
+ );
+ }
+ if (uriMap[URI_DIGITS] != null && uriMap[URI_DIGITS] < 1) {
+ throw LocalizedArgumentError(
+ localizedMessage: (localizations, value, parameter) => localizations.invalidValueForParameter(value, parameter),
+ unlocalizedMessage: 'Digits must be greater than 0',
+ invalidValue: uriMap[URI_DIGITS],
+ name: URI_DIGITS,
);
- } catch (e) {
- throw ArgumentError('Invalid URI: $e');
}
- return dayPasswordToken;
}
- factory DayPasswordToken.fromJson(Map json) => _$DayPasswordTokenFromJson(json);
+ factory DayPasswordToken.fromUriMap(Map uriMap) {
+ validateUriMap(uriMap);
+
+ return DayPasswordToken(
+ label: uriMap[URI_LABEL] ?? '',
+ issuer: uriMap[URI_ISSUER] ?? '',
+ id: const Uuid().v4(),
+ algorithm: Algorithms.values.byName(uriMap[URI_ALGORITHM] ?? 'SHA1'),
+ digits: uriMap[URI_DIGITS] ?? 6,
+ secret: Encodings.base32.encode(uriMap[URI_SECRET]),
+ period: Duration(seconds: uriMap[URI_PERIOD] ?? 86400), // default 24 hours
+ tokenImage: uriMap[URI_IMAGE],
+ pin: uriMap[URI_PIN],
+ isLocked: uriMap[URI_PIN],
+ origin: uriMap[URI_ORIGIN],
+ );
+ }
+
+ @override
Map toJson() => _$DayPasswordTokenToJson(this);
+ factory DayPasswordToken.fromJson(Map json) => _$DayPasswordTokenFromJson(json);
@override
- String toString() {
- return 'DayPassword${super.toString()}period: $period';
- }
+ String toString() => 'DayPassword${super.toString()}period: $period';
}
diff --git a/lib/model/tokens/day_password_token.g.dart b/lib/model/tokens/day_password_token.g.dart
index 3d0663046..ebbb0e7d0 100644
--- a/lib/model/tokens/day_password_token.g.dart
+++ b/lib/model/tokens/day_password_token.g.dart
@@ -9,8 +9,6 @@ part of 'day_password_token.dart';
DayPasswordToken _$DayPasswordTokenFromJson(Map json) =>
DayPasswordToken(
period: Duration(microseconds: json['period'] as int),
- label: json['label'] as String,
- issuer: json['issuer'] as String,
id: json['id'] as String,
algorithm: $enumDecode(_$AlgorithmsEnumMap, json['algorithm']),
digits: json['digits'] as int,
@@ -28,6 +26,8 @@ DayPasswordToken _$DayPasswordTokenFromJson(Map json) =>
origin: json['origin'] == null
? null
: TokenOriginData.fromJson(json['origin'] as Map),
+ label: json['label'] as String? ?? '',
+ issuer: json['issuer'] as String? ?? '',
);
Map _$DayPasswordTokenToJson(DayPasswordToken instance) =>
diff --git a/lib/model/tokens/hotp_token.dart b/lib/model/tokens/hotp_token.dart
index 2a261f568..75f092f02 100644
--- a/lib/model/tokens/hotp_token.dart
+++ b/lib/model/tokens/hotp_token.dart
@@ -1,15 +1,13 @@
import 'package:json_annotation/json_annotation.dart';
-import 'package:otp/otp.dart' as otp_library;
import 'package:uuid/uuid.dart';
-import '../../utils/crypto_utils.dart';
import '../../utils/identifiers.dart';
-import '../../utils/utils.dart';
import '../enums/algorithms.dart';
import '../enums/encodings.dart';
import '../enums/token_types.dart';
-import '../extensions/enum_extension.dart';
-import '../token_origin.dart';
+import '../extensions/enums/algorithms_extension.dart';
+import '../extensions/enums/encodings_extension.dart';
+import '../token_import/token_origin_data.dart';
import 'otp_token.dart';
import 'token.dart';
@@ -17,7 +15,7 @@ part 'hotp_token.g.dart';
@JsonSerializable()
class HOTPToken extends OTPToken {
- static String get tokenType => TokenTypes.HOTP.asString;
+ static String get tokenType => TokenTypes.HOTP.name;
final int counter; // this value is used to calculate the current otp value
@override
@@ -25,33 +23,34 @@ class HOTPToken extends OTPToken {
HOTPToken({
this.counter = 0,
- required super.label,
- required super.issuer,
required super.id,
required super.algorithm,
required super.digits,
required super.secret,
String? type, // just for @JsonSerializable(): type of HOTPToken is always TokenTypes.HOTP
super.tokenImage,
- super.sortIndex,
super.pin,
super.isLocked,
super.isHidden,
+ super.sortIndex,
super.folderId,
super.origin,
- }) : super(type: TokenTypes.HOTP.asString);
+ super.label = '',
+ super.issuer = '',
+ }) : super(type: TokenTypes.HOTP.name);
@override
- bool sameValuesAs(Token other) {
- return super.sameValuesAs(other) && other is HOTPToken && other.counter == counter;
- }
+ bool sameValuesAs(Token other) => super.sameValuesAs(other) && other is HOTPToken && other.counter == counter;
@override
- String get otpValue => otp_library.OTP.generateHOTPCodeString(
- secret,
- counter,
+ // Counter can be changed even if its the same token
+ bool isSameTokenAs(Token other) => super.isSameTokenAs(other) && other is HOTPToken;
+
+ @override
+ String get otpValue => algorithm.generateHOTPCodeString(
+ secret: secret,
+ counter: counter,
length: digits,
- algorithm: algorithm.otpLibraryAlgorithm,
isGoogle: true,
);
@@ -67,10 +66,10 @@ class HOTPToken extends OTPToken {
int? digits,
String? secret,
String? tokenImage,
- int? sortIndex,
bool? pin,
bool? isLocked,
bool? isHidden,
+ int? sortIndex,
int? Function()? folderId,
TokenOriginData? origin,
}) =>
@@ -83,10 +82,10 @@ class HOTPToken extends OTPToken {
digits: digits ?? this.digits,
secret: secret ?? this.secret,
tokenImage: tokenImage ?? this.tokenImage,
- sortIndex: sortIndex ?? this.sortIndex,
pin: pin ?? this.pin,
isLocked: isLocked ?? this.isLocked,
isHidden: isHidden ?? this.isHidden,
+ sortIndex: sortIndex ?? this.sortIndex,
folderId: folderId != null ? folderId() : this.folderId,
origin: origin ?? this.origin,
);
@@ -99,27 +98,22 @@ class HOTPToken extends OTPToken {
factory HOTPToken.fromUriMap(Map uriMap) {
if (uriMap[URI_SECRET] == null) throw ArgumentError('Secret is required');
if (uriMap[URI_DIGITS] < 1) throw ArgumentError('Digits must be greater than 0');
- HOTPToken hotpToken;
- try {
- hotpToken = HOTPToken(
- label: uriMap[URI_LABEL] ?? '',
- issuer: uriMap[URI_ISSUER] ?? '',
- id: const Uuid().v4(),
- algorithm: mapStringToAlgorithm(uriMap[URI_ALGORITHM] ?? 'SHA1'),
- digits: uriMap[URI_DIGITS] ?? 6,
- secret: encodeSecretAs(uriMap[URI_SECRET], Encodings.base32),
- counter: uriMap[URI_COUNTER] ?? 0,
- tokenImage: uriMap[URI_IMAGE],
- pin: uriMap[URI_PIN],
- isLocked: uriMap[URI_PIN],
- );
- } catch (e) {
- throw ArgumentError('Invalid URI: $e');
- }
- return hotpToken;
+ return HOTPToken(
+ label: uriMap[URI_LABEL] ?? '',
+ issuer: uriMap[URI_ISSUER] ?? '',
+ id: const Uuid().v4(),
+ algorithm: Algorithms.values.byName(uriMap[URI_ALGORITHM] ?? 'SHA1'),
+ digits: uriMap[URI_DIGITS] ?? 6,
+ secret: Encodings.base32.encode(uriMap[URI_SECRET]),
+ counter: uriMap[URI_COUNTER] ?? 0,
+ tokenImage: uriMap[URI_IMAGE],
+ pin: uriMap[URI_PIN],
+ isLocked: uriMap[URI_PIN],
+ origin: uriMap[URI_ORIGIN],
+ );
}
- factory HOTPToken.fromJson(Map json) => _$HOTPTokenFromJson(json);
-
+ @override
Map toJson() => _$HOTPTokenToJson(this);
+ factory HOTPToken.fromJson(Map json) => _$HOTPTokenFromJson(json);
}
diff --git a/lib/model/tokens/hotp_token.g.dart b/lib/model/tokens/hotp_token.g.dart
index 513808d66..b8ef1d22d 100644
--- a/lib/model/tokens/hotp_token.g.dart
+++ b/lib/model/tokens/hotp_token.g.dart
@@ -8,22 +8,22 @@ part of 'hotp_token.dart';
HOTPToken _$HOTPTokenFromJson(Map json) => HOTPToken(
counter: json['counter'] as int? ?? 0,
- label: json['label'] as String,
- issuer: json['issuer'] as String,
id: json['id'] as String,
algorithm: $enumDecode(_$AlgorithmsEnumMap, json['algorithm']),
digits: json['digits'] as int,
secret: json['secret'] as String,
type: json['type'] as String?,
tokenImage: json['tokenImage'] as String?,
- sortIndex: json['sortIndex'] as int?,
pin: json['pin'] as bool?,
isLocked: json['isLocked'] as bool?,
isHidden: json['isHidden'] as bool?,
+ sortIndex: json['sortIndex'] as int?,
folderId: json['folderId'] as int?,
origin: json['origin'] == null
? null
: TokenOriginData.fromJson(json['origin'] as Map),
+ label: json['label'] as String? ?? '',
+ issuer: json['issuer'] as String? ?? '',
);
Map _$HOTPTokenToJson(HOTPToken instance) => {
diff --git a/lib/model/tokens/otp_token.dart b/lib/model/tokens/otp_token.dart
index 7b6032a1a..36711210e 100644
--- a/lib/model/tokens/otp_token.dart
+++ b/lib/model/tokens/otp_token.dart
@@ -1,5 +1,6 @@
+import '../../utils/logger.dart';
import '../enums/algorithms.dart';
-import '../token_origin.dart';
+import '../token_import/token_origin_data.dart';
import 'token.dart';
abstract class OTPToken extends Token {
@@ -7,27 +8,36 @@ abstract class OTPToken extends Token {
final int digits; // the number of digits the otp value will have
final String secret; // the secret based on which the otp value is calculated in base32
String get otpValue; // the current otp value
+ Duration get showDuration {
+ const Duration duration = Duration(seconds: 30);
+ Logger.info('$runtimeType showDuration: ${duration.inSeconds} seconds');
+ return duration;
+ } // the duration the otp value is shown
const OTPToken({
required this.algorithm,
required this.digits,
required this.secret,
- required super.label,
- required super.issuer,
required super.id,
required super.type,
super.pin,
super.tokenImage,
- super.sortIndex,
super.isLocked,
super.isHidden,
+ super.sortIndex,
super.folderId,
super.origin,
+ super.label = '',
+ super.issuer = '',
});
+ // @override
+ // No changeable value in OTPToken
+ // bool sameValuesAs(Token other) => super.sameValuesAs(other);
+
@override
- bool sameValuesAs(Token other) {
- return super.sameValuesAs(other) && other is OTPToken && other.algorithm == algorithm && other.digits == digits && other.secret == secret;
+ bool isSameTokenAs(Token other) {
+ return super.isSameTokenAs(other) && other is OTPToken && other.algorithm == algorithm && other.digits == digits && other.secret == secret;
}
@override
diff --git a/lib/model/tokens/push_token.dart b/lib/model/tokens/push_token.dart
index e39b0fb66..3239f2191 100644
--- a/lib/model/tokens/push_token.dart
+++ b/lib/model/tokens/push_token.dart
@@ -1,4 +1,3 @@
-import 'package:collection/collection.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:pointycastle/asymmetric/api.dart';
import 'package:uuid/uuid.dart';
@@ -8,10 +7,7 @@ import '../../utils/identifiers.dart';
import '../../utils/rsa_utils.dart';
import '../enums/push_token_rollout_state.dart';
import '../enums/token_types.dart';
-import '../extensions/enum_extension.dart';
-import '../push_request.dart';
-import '../push_request_queue.dart';
-import '../token_origin.dart';
+import '../token_import/token_origin_data.dart';
import 'token.dart';
part 'push_token.g.dart';
@@ -21,9 +17,10 @@ class PushToken extends Token {
static RsaUtils rsaParser = const RsaUtils();
final DateTime? expirationDate;
final String serial;
+ final String? fbToken;
@override
- Duration get showDuration => Duration.zero;
+ bool? get isPrivacyIdeaToken => true;
// Roll out
final bool sslVerify;
@@ -45,32 +42,12 @@ class PushToken extends Token {
RSAPrivateKey? get rsaPrivateTokenKey => privateTokenKey == null ? null : rsaParser.deserializeRSAPrivateKeyPKCS1(privateTokenKey!);
PushToken withPrivateTokenKey(RSAPrivateKey key) => copyWith(privateTokenKey: rsaParser.serializeRSAPrivateKeyPKCS1(key));
- PushToken withPushRequest(PushRequest pr) {
- pushRequests.add(pr);
- knownPushRequests.put(pr.id);
- return copyWith(pushRequests: pushRequests, knownPushRequests: knownPushRequests);
- }
-
- PushToken withoutPushRequest(PushRequest pr) {
- if (pushRequests.list.firstWhereOrNull((element) => element.id == pr.id) != null) {
- pushRequests.remove(pr);
- }
- return copyWith(pushRequests: pushRequests);
- }
-
- late final PushRequestQueue pushRequests;
- final CustomIntBuffer knownPushRequests;
-
- bool knowsRequestWithId(int id) {
- bool exists = pushRequests.any((element) => element.id == id);
- return exists || knownPushRequests.contains(id);
- }
-
PushToken({
required this.serial,
- required super.label,
- required super.issuer,
+ super.label,
+ super.issuer,
required super.id,
+ this.fbToken,
this.url,
this.expirationDate,
this.enrollmentCredentials,
@@ -80,11 +57,9 @@ class PushToken extends Token {
bool? isRolledOut,
bool? sslVerify,
PushTokenRollOutState? rolloutState,
- PushRequestQueue? pushRequests,
- CustomIntBuffer? knownPushRequests,
String? type, // just for @JsonSerializable(): type of PushToken is always TokenTypes.PIPUSH
- super.sortIndex,
super.tokenImage,
+ super.sortIndex,
super.folderId,
super.pin,
super.isLocked,
@@ -93,23 +68,28 @@ class PushToken extends Token {
}) : isRolledOut = isRolledOut ?? false,
sslVerify = sslVerify ?? false,
rolloutState = rolloutState ?? PushTokenRollOutState.rolloutNotStarted,
- knownPushRequests = knownPushRequests ?? CustomIntBuffer(),
- pushRequests = pushRequests ?? PushRequestQueue(),
- super(type: TokenTypes.PIPUSH.asString);
+ super(type: TokenTypes.PIPUSH.name);
@override
bool sameValuesAs(Token other) {
return super.sameValuesAs(other) &&
other is PushToken &&
- other.serial == serial &&
+ other.fbToken == fbToken &&
other.expirationDate == expirationDate &&
other.sslVerify == sslVerify &&
other.enrollmentCredentials == enrollmentCredentials &&
other.url == url &&
- other.isRolledOut == isRolledOut &&
- other.publicServerKey == publicServerKey &&
+ other.isRolledOut == isRolledOut;
+ }
+
+ @override
+ bool isSameTokenAs(Token other) {
+ return super.isSameTokenAs(other) &&
+ other is PushToken &&
+ other.serial == serial &&
+ other.privateTokenKey == privateTokenKey &&
other.publicTokenKey == publicTokenKey &&
- other.privateTokenKey == privateTokenKey;
+ other.publicServerKey == publicServerKey;
}
@override
@@ -119,14 +99,13 @@ class PushToken extends Token {
String? issuer,
String? id,
String? tokenImage,
- PushRequestQueue? pushRequests,
+ String? fbToken,
bool? pin,
bool? isLocked,
bool? isHidden,
bool? sslVerify,
String? enrollmentCredentials,
Uri? url,
- int? sortIndex,
String? publicServerKey,
String? publicTokenKey,
String? privateTokenKey,
@@ -134,6 +113,7 @@ class PushToken extends Token {
bool? isRolledOut,
PushTokenRollOutState? rolloutState,
CustomIntBuffer? knownPushRequests,
+ int? sortIndex,
int? Function()? folderId,
TokenOriginData? origin,
}) {
@@ -142,22 +122,21 @@ class PushToken extends Token {
serial: serial ?? this.serial,
issuer: issuer ?? this.issuer,
tokenImage: tokenImage ?? this.tokenImage,
+ fbToken: fbToken ?? this.fbToken,
id: id ?? this.id,
- pushRequests: pushRequests ?? this.pushRequests,
pin: pin ?? this.pin,
isLocked: isLocked ?? this.isLocked,
isHidden: isHidden ?? this.isHidden,
sslVerify: sslVerify ?? this.sslVerify,
enrollmentCredentials: enrollmentCredentials ?? this.enrollmentCredentials,
url: url ?? this.url,
- sortIndex: sortIndex ?? this.sortIndex,
publicServerKey: publicServerKey ?? this.publicServerKey,
publicTokenKey: publicTokenKey ?? this.publicTokenKey,
privateTokenKey: privateTokenKey ?? this.privateTokenKey,
expirationDate: expirationDate ?? this.expirationDate,
isRolledOut: isRolledOut ?? this.isRolledOut,
rolloutState: rolloutState ?? this.rolloutState,
- knownPushRequests: knownPushRequests ?? this.knownPushRequests,
+ sortIndex: sortIndex ?? this.sortIndex,
folderId: folderId != null ? folderId() : this.folderId,
origin: origin ?? this.origin,
);
@@ -180,15 +159,11 @@ class PushToken extends Token {
'isRolledOut: $isRolledOut, '
'rolloutState: $rolloutState, '
'publicServerKey: $publicServerKey, '
- 'publicTokenKey: $publicTokenKey, '
- 'pushRequests: $pushRequests, '
- 'knownPushRequests: $knownPushRequests}';
+ 'privateTokenKey: $privateTokenKey, '
+ 'publicTokenKey: $publicTokenKey}';
}
- factory PushToken.fromUriMap(Map uriMap) {
- PushToken pushToken;
- try {
- pushToken = PushToken(
+ factory PushToken.fromUriMap(Map uriMap) => PushToken(
serial: uriMap[URI_SERIAL] ?? '',
label: uriMap[URI_LABEL] ?? '',
issuer: uriMap[URI_ISSUER] ?? '',
@@ -200,16 +175,11 @@ class PushToken extends Token {
tokenImage: uriMap[URI_IMAGE],
pin: uriMap[URI_PIN],
isLocked: uriMap[URI_PIN],
+ origin: uriMap[URI_ORIGIN],
);
- } catch (e) {
- throw ArgumentError('Invalid URI: $e');
- }
- return pushToken;
- }
factory PushToken.fromJson(Map json) {
final newToken = _$PushTokenFromJson(json);
- newToken.pushRequests.removeWhere((request) => request.expirationDate.isBefore(DateTime.now()));
final currentRolloutState = switch (newToken.rolloutState) {
PushTokenRollOutState.rolloutNotStarted => PushTokenRollOutState.rolloutNotStarted,
PushTokenRollOutState.generatingRSAKeyPair || PushTokenRollOutState.generatingRSAKeyPairFailed => PushTokenRollOutState.generatingRSAKeyPairFailed,
@@ -220,5 +190,6 @@ class PushToken extends Token {
return newToken.copyWith(rolloutState: currentRolloutState);
}
+ @override
Map toJson() => _$PushTokenToJson(this);
}
diff --git a/lib/model/tokens/push_token.g.dart b/lib/model/tokens/push_token.g.dart
index a38b45102..2f3acccfa 100644
--- a/lib/model/tokens/push_token.g.dart
+++ b/lib/model/tokens/push_token.g.dart
@@ -8,9 +8,10 @@ part of 'push_token.dart';
PushToken _$PushTokenFromJson(Map json) => PushToken(
serial: json['serial'] as String,
- label: json['label'] as String,
- issuer: json['issuer'] as String,
+ label: json['label'] as String? ?? '',
+ issuer: json['issuer'] as String? ?? '',
id: json['id'] as String,
+ fbToken: json['fbToken'] as String?,
url: json['url'] == null ? null : Uri.parse(json['url'] as String),
expirationDate: json['expirationDate'] == null
? null
@@ -23,17 +24,9 @@ PushToken _$PushTokenFromJson(Map json) => PushToken(
sslVerify: json['sslVerify'] as bool?,
rolloutState: $enumDecodeNullable(
_$PushTokenRollOutStateEnumMap, json['rolloutState']),
- pushRequests: json['pushRequests'] == null
- ? null
- : PushRequestQueue.fromJson(
- json['pushRequests'] as Map),
- knownPushRequests: json['knownPushRequests'] == null
- ? null
- : CustomIntBuffer.fromJson(
- json['knownPushRequests'] as Map),
type: json['type'] as String?,
- sortIndex: json['sortIndex'] as int?,
tokenImage: json['tokenImage'] as String?,
+ sortIndex: json['sortIndex'] as int?,
folderId: json['folderId'] as int?,
pin: json['pin'] as bool?,
isLocked: json['isLocked'] as bool?,
@@ -57,6 +50,7 @@ Map _$PushTokenToJson(PushToken instance) => {
'type': instance.type,
'expirationDate': instance.expirationDate?.toIso8601String(),
'serial': instance.serial,
+ 'fbToken': instance.fbToken,
'sslVerify': instance.sslVerify,
'enrollmentCredentials': instance.enrollmentCredentials,
'url': instance.url?.toString(),
@@ -65,8 +59,6 @@ Map _$PushTokenToJson(PushToken instance) => {
'publicServerKey': instance.publicServerKey,
'privateTokenKey': instance.privateTokenKey,
'publicTokenKey': instance.publicTokenKey,
- 'pushRequests': instance.pushRequests,
- 'knownPushRequests': instance.knownPushRequests,
};
const _$PushTokenRollOutStateEnumMap = {
diff --git a/lib/model/tokens/steam_token.dart b/lib/model/tokens/steam_token.dart
new file mode 100644
index 000000000..4800e9b84
--- /dev/null
+++ b/lib/model/tokens/steam_token.dart
@@ -0,0 +1,129 @@
+import 'package:base32/base32.dart';
+import 'package:crypto/crypto.dart';
+import 'package:json_annotation/json_annotation.dart';
+import 'package:uuid/uuid.dart';
+
+import '../../utils/errors.dart';
+import '../../utils/identifiers.dart';
+import '../enums/algorithms.dart';
+import '../enums/encodings.dart';
+import '../enums/token_types.dart';
+import '../extensions/enums/encodings_extension.dart';
+import '../extensions/int_extension.dart';
+import '../token_import/token_origin_data.dart';
+import 'token.dart';
+import 'totp_token.dart';
+
+part 'steam_token.g.dart';
+
+@JsonSerializable()
+class SteamToken extends TOTPToken {
+ @override
+ bool get isPrivacyIdeaToken => false;
+ static String get tokenType => TokenTypes.STEAM.name;
+ static const String steamAlphabet = "23456789BCDFGHJKMNPQRTVWXY";
+
+ SteamToken({
+ required super.id,
+ required super.secret,
+ String? type,
+ super.tokenImage,
+ super.pin,
+ super.isLocked,
+ super.isHidden,
+ super.sortIndex,
+ super.folderId,
+ super.origin,
+ super.label = '',
+ super.issuer = '',
+ }) : super(
+ type: type ?? tokenType,
+ period: 30,
+ digits: 5,
+ algorithm: Algorithms.SHA1,
+ );
+
+ @override
+ SteamToken copyWith({
+ String? label,
+ String? issuer,
+ String? id,
+ bool? isLocked,
+ bool? isHidden,
+ bool? pin,
+ String? tokenImage,
+ int? sortIndex,
+ int? Function()? folderId,
+ TokenOriginData? origin,
+ int? period, // unused steam tokens always have 30 seconds period
+ int? digits, // unused steam tokens always have 5 digits
+ Algorithms? algorithm, // unused steam tokens always have SHA1 algorithm
+ String? secret,
+ }) {
+ return SteamToken(
+ label: label ?? this.label,
+ issuer: issuer ?? this.issuer,
+ id: id ?? this.id,
+ secret: secret ?? this.secret,
+ tokenImage: tokenImage ?? this.tokenImage,
+ pin: pin ?? this.pin,
+ isLocked: isLocked ?? this.isLocked,
+ isHidden: isHidden ?? this.isHidden,
+ sortIndex: sortIndex ?? this.sortIndex,
+ folderId: folderId != null ? folderId() : this.folderId,
+ origin: origin ?? this.origin,
+ );
+ }
+
+ // @override
+ /// No changeable value in SteamToken
+ // bool sameValuesAs(Token other) => super.sameValuesAs(other);
+
+ @override
+ bool isSameTokenAs(Token other) => super.isSameTokenAs(other) && other is SteamToken;
+
+ String otpOfTime(DateTime time) {
+ // Flooring time/counter is TOTP default, but yes, steam uses the rounded time/counter.
+ final counterBytes = (time.millisecondsSinceEpoch / 1000 / period).round().bytes;
+ final secretList = base32.decode(secret.toUpperCase());
+ final hmac = Hmac(sha1, secretList);
+ final digest = hmac.convert(counterBytes).bytes;
+ final offset = digest[digest.length - 1] & 0x0f;
+
+ var code = ((digest[offset] & 0x7f) << 24) | ((digest[offset + 1] & 0xff) << 16) | ((digest[offset + 2] & 0xff) << 8) | (digest[offset + 3] & 0xff);
+
+ final stringBuffer = StringBuffer();
+ for (int i = 0; i < digits; i++) {
+ stringBuffer.write(steamAlphabet[code % steamAlphabet.length]);
+ code ~/= steamAlphabet.length;
+ }
+ return stringBuffer.toString();
+ }
+
+ @override
+ String get otpValue => otpOfTime(DateTime.now());
+
+ static SteamToken fromUriMap(Map uriMap) {
+ if (uriMap[URI_SECRET] == null) {
+ throw LocalizedArgumentError(
+ localizedMessage: (localizations, value, name) => localizations.secretIsRequired,
+ unlocalizedMessage: 'Secret is required',
+ invalidValue: uriMap[URI_SECRET],
+ name: 'SteamToken#fromUriMap',
+ );
+ }
+ return SteamToken(
+ label: (uriMap[URI_LABEL] as String?) ?? '',
+ issuer: (uriMap[URI_ISSUER] as String?) ?? '',
+ id: const Uuid().v4(),
+ secret: Encodings.base32.encode(uriMap[URI_SECRET]),
+ tokenImage: uriMap[URI_IMAGE] as String?,
+ pin: uriMap[URI_PIN] as bool?,
+ origin: uriMap[URI_ORIGIN] as TokenOriginData?,
+ );
+ }
+
+ static SteamToken fromJson(Map json) => _$SteamTokenFromJson(json);
+ @override
+ Map toJson() => _$SteamTokenToJson(this);
+}
diff --git a/lib/model/tokens/steam_token.g.dart b/lib/model/tokens/steam_token.g.dart
new file mode 100644
index 000000000..68a5d14ab
--- /dev/null
+++ b/lib/model/tokens/steam_token.g.dart
@@ -0,0 +1,40 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'steam_token.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SteamToken _$SteamTokenFromJson(Map json) => SteamToken(
+ id: json['id'] as String,
+ secret: json['secret'] as String,
+ type: json['type'] as String?,
+ tokenImage: json['tokenImage'] as String?,
+ pin: json['pin'] as bool?,
+ isLocked: json['isLocked'] as bool?,
+ isHidden: json['isHidden'] as bool?,
+ sortIndex: json['sortIndex'] as int?,
+ folderId: json['folderId'] as int?,
+ origin: json['origin'] == null
+ ? null
+ : TokenOriginData.fromJson(json['origin'] as Map),
+ label: json['label'] as String? ?? '',
+ issuer: json['issuer'] as String? ?? '',
+ );
+
+Map _$SteamTokenToJson(SteamToken instance) =>
+ {
+ 'label': instance.label,
+ 'issuer': instance.issuer,
+ 'id': instance.id,
+ 'pin': instance.pin,
+ 'isLocked': instance.isLocked,
+ 'isHidden': instance.isHidden,
+ 'tokenImage': instance.tokenImage,
+ 'folderId': instance.folderId,
+ 'sortIndex': instance.sortIndex,
+ 'origin': instance.origin,
+ 'type': instance.type,
+ 'secret': instance.secret,
+ };
diff --git a/lib/model/tokens/token.dart b/lib/model/tokens/token.dart
index 63a987135..6d55e8cea 100644
--- a/lib/model/tokens/token.dart
+++ b/lib/model/tokens/token.dart
@@ -4,14 +4,16 @@ import '../../utils/identifiers.dart';
import '../enums/token_types.dart';
import '../extensions/enum_extension.dart';
import '../mixins/sortable_mixin.dart';
-import '../token_origin.dart';
+import '../token_import/token_origin_data.dart';
import 'day_password_token.dart';
import 'hotp_token.dart';
import 'push_token.dart';
+import 'steam_token.dart';
import 'totp_token.dart';
@immutable
abstract class Token with SortableMixin {
+ bool? get isPrivacyIdeaToken => origin?.isPrivacyIdeaToken;
final String tokenVersion = 'v1.0.0'; // The version of this token, this is used for serialization.
final String label; // the name of the token, it cannot be uses as an identifier
final String issuer; // The issuer of this token, currently unused.
@@ -19,12 +21,10 @@ abstract class Token with SortableMixin {
final bool pin;
final bool isLocked;
final bool isHidden;
- Duration get showDuration;
final String? tokenImage;
final int? folderId;
@override
final int? sortIndex;
-
final TokenOriginData? origin;
// Must be string representation of TokenType enum.
@@ -32,26 +32,28 @@ abstract class Token with SortableMixin {
factory Token.fromJson(Map json) {
String type = json['type'];
- if (TokenTypes.HOTP.isString(type)) return HOTPToken.fromJson(json);
- if (TokenTypes.TOTP.isString(type)) return TOTPToken.fromJson(json);
- if (TokenTypes.PIPUSH.isString(type)) return PushToken.fromJson(json);
- if (TokenTypes.DAYPASSWORD.isString(type)) return DayPasswordToken.fromJson(json);
- throw ArgumentError.value(json, 'json', 'Building the token type [$type] is not a supported right now.');
+ if (TokenTypes.HOTP.isName(type, caseSensitive: false)) return HOTPToken.fromJson(json);
+ if (TokenTypes.TOTP.isName(type, caseSensitive: false)) return TOTPToken.fromJson(json);
+ if (TokenTypes.PIPUSH.isName(type, caseSensitive: false)) return PushToken.fromJson(json);
+ if (TokenTypes.DAYPASSWORD.isName(type, caseSensitive: false)) return DayPasswordToken.fromJson(json);
+ if (TokenTypes.STEAM.isName(type, caseSensitive: false)) return SteamToken.fromJson(json);
+ throw ArgumentError.value(json, 'Token#fromJson', 'Token type [$type] is not a supported');
}
factory Token.fromUriMap(
Map uriMap,
) {
String type = uriMap[URI_TYPE];
- if (TokenTypes.HOTP.isString(type)) return HOTPToken.fromUriMap(uriMap);
- if (TokenTypes.TOTP.isString(type)) return TOTPToken.fromUriMap(uriMap);
- if (TokenTypes.PIPUSH.isString(type)) return PushToken.fromUriMap(uriMap);
- if (TokenTypes.DAYPASSWORD.isString(type)) return DayPasswordToken.fromUriMap(uriMap);
- throw ArgumentError.value(uriMap, 'uri', 'Building the token type [$type] is not a supported right now.');
+ if (TokenTypes.HOTP.isName(type, caseSensitive: false)) return HOTPToken.fromUriMap(uriMap);
+ if (TokenTypes.TOTP.isName(type, caseSensitive: false)) return TOTPToken.fromUriMap(uriMap);
+ if (TokenTypes.PIPUSH.isName(type, caseSensitive: false)) return PushToken.fromUriMap(uriMap);
+ if (TokenTypes.DAYPASSWORD.isName(type, caseSensitive: false)) return DayPasswordToken.fromUriMap(uriMap);
+ if (TokenTypes.STEAM.isName(type, caseSensitive: false)) return SteamToken.fromUriMap(uriMap);
+ throw ArgumentError.value(uriMap, 'Token#fromUriMap', 'Token type [$type] is not a supported');
}
const Token({
- required this.label,
- required this.issuer,
+ this.label = '',
+ this.issuer = '',
required this.id,
required this.type,
this.tokenImage,
@@ -66,16 +68,13 @@ abstract class Token with SortableMixin {
isHidden = (pin != null && pin ? true : isLocked ?? false) == false ? false : isHidden ?? false,
pin = pin ?? false;
- /// If the type and the id are the same the tokens it is the same token (== operator).
- /// But [sameValuesAs] is used to check if a different token has the same values as this token.
- /// Id is here ignored because it is only used to identify the same the token.
- bool sameValuesAs(Token other) {
- return other.label == label &&
- other.issuer == issuer &&
- other.pin == pin &&
- other.isLocked == isLocked &&
- other.tokenImage == tokenImage &&
- other.type == type;
+ /// This is used to compare the changeable values of the token.
+ bool sameValuesAs(Token other) =>
+ other.label == label && other.issuer == issuer && other.pin == pin && other.isLocked == isLocked && other.tokenImage == tokenImage;
+
+ /// This is used to identify the same token even if the id is different.
+ bool isSameTokenAs(Token other) {
+ return other.type == type; // && other.origin?.appName == origin?.appName && other.origin?.data == origin?.data;
}
@override
@@ -114,4 +113,6 @@ abstract class Token with SortableMixin {
'folderId: $folderId, '
'origin: $origin, ';
}
+
+ Map toJson();
}
diff --git a/lib/model/tokens/totp_token.dart b/lib/model/tokens/totp_token.dart
index 882747402..75f0db286 100644
--- a/lib/model/tokens/totp_token.dart
+++ b/lib/model/tokens/totp_token.dart
@@ -1,16 +1,14 @@
import 'package:json_annotation/json_annotation.dart';
-import 'package:otp/otp.dart' as otp_library;
import 'package:uuid/uuid.dart';
-import '../../utils/crypto_utils.dart';
import '../../utils/identifiers.dart';
import '../../utils/logger.dart';
-import '../../utils/utils.dart';
import '../enums/algorithms.dart';
import '../enums/encodings.dart';
import '../enums/token_types.dart';
-import '../extensions/enum_extension.dart';
-import '../token_origin.dart';
+import '../extensions/enums/algorithms_extension.dart';
+import '../extensions/enums/encodings_extension.dart';
+import '../token_import/token_origin_data.dart';
import 'otp_token.dart';
import 'token.dart';
@@ -18,7 +16,7 @@ part 'totp_token.g.dart';
@JsonSerializable()
class TOTPToken extends OTPToken {
- static String get tokenType => TokenTypes.TOTP.asString;
+ static String get tokenType => TokenTypes.TOTP.name;
// this value is used to calculate the current 'counter' of this token
// based on the UNIX systemtime), the counter is used to calculate the
// current otp value
@@ -26,44 +24,47 @@ class TOTPToken extends OTPToken {
@override
Duration get showDuration {
final Duration duration = Duration(milliseconds: (period * 1000 + (secondsUntilNextOTP * 1000).toInt()));
- Logger.warning('TOTPToken.showDuration: $duration');
+ Logger.info('$runtimeType showDuration: ${duration.inSeconds} seconds');
return duration;
}
final int period;
- @override
- String get otpValue => otp_library.OTP.generateTOTPCodeString(
- secret,
- DateTime.now().millisecondsSinceEpoch,
+ String otpFromTime(DateTime time) => algorithm.generateTOTPCodeString(
+ secret: secret,
+ time: time,
length: digits,
- algorithm: algorithm.otpLibraryAlgorithm,
- interval: period,
+ interval: Duration(seconds: period),
isGoogle: true,
);
+ @override
+ String get otpValue => otpFromTime(DateTime.now());
+
TOTPToken({
required int period,
- required super.label,
- required super.issuer,
required super.id,
required super.algorithm,
required super.digits,
required super.secret,
- String? type, // just for @JsonSerializable(): type of TOTPToken is always TokenTypes.TOTP
+ String? type,
super.tokenImage,
- super.sortIndex,
super.pin,
super.isLocked,
super.isHidden,
+ super.sortIndex,
super.folderId,
super.origin,
+ super.label = '',
+ super.issuer = '',
}) : period = period < 1 ? 30 : period, // period must be greater than 0 otherwise IntegerDivisionByZeroException is thrown in OTP.generateTOTPCodeString
- super(type: TokenTypes.TOTP.asString);
+ super(type: type ?? tokenType);
+
+ // @override
+ // No changeable value in TOTPToken
+ // bool sameValuesAs(Token other) => super.sameValuesAs(other);
@override
- bool sameValuesAs(Token other) {
- return super.sameValuesAs(other) && other is TOTPToken && other.period == period;
- }
+ bool isSameTokenAs(Token other) => super.isSameTokenAs(other) && other is TOTPToken && other.period == period;
@override
TOTPToken copyWith({
@@ -75,10 +76,10 @@ class TOTPToken extends OTPToken {
String? secret,
int? period,
String? tokenImage,
- int? sortIndex,
bool? pin,
bool? isLocked,
bool? isHidden,
+ int? sortIndex,
int? Function()? folderId,
TokenOriginData? origin,
}) {
@@ -91,10 +92,10 @@ class TOTPToken extends OTPToken {
secret: secret ?? this.secret,
period: period ?? this.period,
tokenImage: tokenImage ?? this.tokenImage,
- sortIndex: sortIndex ?? this.sortIndex,
pin: pin ?? this.pin,
isLocked: isLocked ?? this.isLocked,
isHidden: isHidden ?? this.isHidden,
+ sortIndex: sortIndex ?? this.sortIndex,
folderId: folderId != null ? folderId() : this.folderId,
origin: origin ?? this.origin,
);
@@ -109,24 +110,19 @@ class TOTPToken extends OTPToken {
if (uriMap[URI_SECRET] == null) throw ArgumentError('Secret is required');
if (uriMap[URI_DIGITS] != null && uriMap[URI_DIGITS] < 1) throw ArgumentError('Digits must be greater than 0');
if (uriMap[URI_PERIOD] != null && uriMap[URI_PERIOD] < 1) throw ArgumentError('Period must be greater than 0');
- TOTPToken totpToken;
- try {
- totpToken = TOTPToken(
- label: uriMap[URI_LABEL] ?? '',
- issuer: uriMap[URI_ISSUER] ?? '',
- id: const Uuid().v4(),
- algorithm: mapStringToAlgorithm(uriMap[URI_ALGORITHM] ?? 'SHA1'),
- digits: uriMap[URI_DIGITS] ?? 6,
- tokenImage: uriMap[URI_IMAGE],
- secret: encodeSecretAs(uriMap[URI_SECRET], Encodings.base32),
- period: uriMap[URI_PERIOD] ?? 30,
- pin: uriMap[URI_PIN],
- isLocked: uriMap[URI_PIN],
- );
- } catch (e) {
- throw ArgumentError('Invalid URI: $e');
- }
- return totpToken;
+ return TOTPToken(
+ label: uriMap[URI_LABEL] ?? '',
+ issuer: uriMap[URI_ISSUER] ?? '',
+ id: const Uuid().v4(),
+ algorithm: Algorithms.values.byName((uriMap[URI_ALGORITHM] ?? 'SHA1')),
+ digits: uriMap[URI_DIGITS] ?? 6,
+ tokenImage: uriMap[URI_IMAGE],
+ secret: Encodings.base32.encode(uriMap[URI_SECRET]),
+ period: uriMap[URI_PERIOD] ?? 30,
+ pin: uriMap[URI_PIN],
+ isLocked: uriMap[URI_PIN],
+ origin: uriMap[URI_ORIGIN],
+ );
}
double get currentProgress {
@@ -139,6 +135,7 @@ class TOTPToken extends OTPToken {
return period - (secondsSinceEpoch % (period));
}
+ @override
Map