Compare commits
978 Commits
fdroid-v0.
...
cli-v0.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa7c417e69 | ||
|
|
affb9bb783 | ||
|
|
8d737f79b5 | ||
|
|
41b20a6b48 | ||
|
|
fcd1554f7c | ||
|
|
fe37bb5544 | ||
|
|
6493e54db9 | ||
|
|
d23cab124e | ||
|
|
ee0ebe8602 | ||
|
|
a9da87881d | ||
|
|
89815d47ff | ||
|
|
2cc1573b1b | ||
|
|
160565f216 | ||
|
|
6f84371cfa | ||
|
|
7c07c8dadb | ||
|
|
27c191eaf1 | ||
|
|
6872587083 | ||
|
|
bc7f4fd9fc | ||
|
|
7bf37c2800 | ||
|
|
215126f695 | ||
|
|
0aad23d860 | ||
|
|
34762cc303 | ||
|
|
b254bb5b0c | ||
|
|
c80a066518 | ||
|
|
00ffe8f129 | ||
|
|
70ee3e3fbe | ||
|
|
f37f807045 | ||
|
|
6254fe032b | ||
|
|
63138a539a | ||
|
|
37765169a4 | ||
|
|
b7a45b4327 | ||
|
|
1521971a5d | ||
|
|
d62ca44675 | ||
|
|
02c428971c | ||
|
|
beabb4815b | ||
|
|
87f9537bb2 | ||
|
|
69a5795c86 | ||
|
|
212ab374ac | ||
|
|
dc23c7eebd | ||
|
|
31459d9339 | ||
|
|
5cc4a5ed07 | ||
|
|
cda7dda3cb | ||
|
|
6b831378ba | ||
|
|
49b34bdb19 | ||
|
|
bf17902e73 | ||
|
|
3fa85b4ce9 | ||
|
|
8b4d38a50a | ||
|
|
57e2ff4908 | ||
|
|
f890f612f4 | ||
|
|
038a40b320 | ||
|
|
5fa05e3406 | ||
|
|
3577b1f213 | ||
|
|
9df36a50bf | ||
|
|
7e16f4f5be | ||
|
|
30b508fa56 | ||
|
|
d308eb9274 | ||
|
|
b4c6805d42 | ||
|
|
9c1f744f73 | ||
|
|
5ce1a91146 | ||
|
|
41512540e4 | ||
|
|
2c4dd13ab0 | ||
|
|
637974f63b | ||
|
|
70fdfb6901 | ||
|
|
4e7d9ed7d9 | ||
|
|
5da924f7e4 | ||
|
|
2988767f97 | ||
|
|
232d02a990 | ||
|
|
df13dd2bfc | ||
|
|
18a7fce523 | ||
|
|
c03b3fd203 | ||
|
|
42ce7a0d39 | ||
|
|
bcd1fd0cc8 | ||
|
|
e799843c59 | ||
|
|
fff633aebe | ||
|
|
63144d50fc | ||
|
|
0431493736 | ||
|
|
7d647cf4f1 | ||
|
|
e66c4390bb | ||
|
|
df44e6d1a9 | ||
|
|
fd29a982cc | ||
|
|
6720f16ceb | ||
|
|
8685bae282 | ||
|
|
72c1d83714 | ||
|
|
bf65faef33 | ||
|
|
29503a077d | ||
|
|
f2f332062f | ||
|
|
e79e932014 | ||
|
|
f5dba2f36e | ||
|
|
9f92787ac6 | ||
|
|
66c3870518 | ||
|
|
98e0aeee8a | ||
|
|
785cac2c70 | ||
|
|
258c47eba4 | ||
|
|
466ec23248 | ||
|
|
3c7b8fd0e8 | ||
|
|
6a1021c353 | ||
|
|
6e07aacc3f | ||
|
|
454f498a7c | ||
|
|
9169b344fb | ||
|
|
13e6c982a6 | ||
|
|
3d096311f4 | ||
|
|
a97dddf8e5 | ||
|
|
23574a2e3a | ||
|
|
ce5354e19d | ||
|
|
d11aeee29c | ||
|
|
776881d75f | ||
|
|
b9eef77d3a | ||
|
|
93ab5f4a84 | ||
|
|
50e8757c8f | ||
|
|
a5f543151b | ||
|
|
2d0ceebb43 | ||
|
|
17991bb6fc | ||
|
|
64090ad9ee | ||
|
|
9e26397c1b | ||
|
|
aed48026c3 | ||
|
|
7911c14e40 | ||
|
|
c315bc9da1 | ||
|
|
6fe4c0147a | ||
|
|
5e7c5e0d6f | ||
|
|
802ba2bc5b | ||
|
|
fb4f5c2095 | ||
|
|
9ce8470af5 | ||
|
|
e0fe62e717 | ||
|
|
8056720e23 | ||
|
|
e6d4e835db | ||
|
|
f4995cba56 | ||
|
|
73a323d927 | ||
|
|
8ed58127e1 | ||
|
|
9c975eae69 | ||
|
|
139e47867d | ||
|
|
6008243c86 | ||
|
|
04afcbe678 | ||
|
|
6c603cb012 | ||
|
|
6d1ab3f1ca | ||
|
|
660b5160f2 | ||
|
|
964075a32c | ||
|
|
d25420c867 | ||
|
|
a9c646ca77 | ||
|
|
10d6e18332 | ||
|
|
0feb5519ba | ||
|
|
30a2752f9d | ||
|
|
608234d4ed | ||
|
|
2a8eb2aaf7 | ||
|
|
304a7df033 | ||
|
|
52fe082bae | ||
|
|
3a45640a17 | ||
|
|
5c1b3886ed | ||
|
|
3a10c853d0 | ||
|
|
4f00a87e29 | ||
|
|
2db5ca81f5 | ||
|
|
3352e2a075 | ||
|
|
266d75a574 | ||
|
|
217d4d950e | ||
|
|
c42ebf3377 | ||
|
|
d3b30052e2 | ||
|
|
490996193a | ||
|
|
02d69b3b1c | ||
|
|
0ea77ee1f4 | ||
|
|
0379d14640 | ||
|
|
6d316d25d3 | ||
|
|
6ba88d5d19 | ||
|
|
34a8dc21c6 | ||
|
|
864d150552 | ||
|
|
fbef356ab5 | ||
|
|
0947b2bbaa | ||
|
|
b74de7f424 | ||
|
|
651899cd23 | ||
|
|
534250320c | ||
|
|
deef4886eb | ||
|
|
58b82b46f3 | ||
|
|
82712e9313 | ||
|
|
accf563519 | ||
|
|
e8acaf7457 | ||
|
|
b5f8964dc4 | ||
|
|
0275d08e27 | ||
|
|
75c3bc1c84 | ||
|
|
08a77a2def | ||
|
|
74dc15c38c | ||
|
|
baeb47f94b | ||
|
|
ef5f58e5a2 | ||
|
|
d77f4af04b | ||
|
|
0c8f05076a | ||
|
|
023a13927c | ||
|
|
c8c3d8f814 | ||
|
|
9400f2e134 | ||
|
|
8cd43e9e4b | ||
|
|
44d66da742 | ||
|
|
bc0d6adfd1 | ||
|
|
cc80453b12 | ||
|
|
816d74a5e6 | ||
|
|
710bb61f21 | ||
|
|
d649cbd9fa | ||
|
|
85fe4b317d | ||
|
|
623f2c1985 | ||
|
|
5bcb8fe2ea | ||
|
|
b8f2b850c3 | ||
|
|
d976986473 | ||
|
|
e6ad4db6d6 | ||
|
|
897dd78ffd | ||
|
|
016761be9a | ||
|
|
2990ba855f | ||
|
|
09f65eeff7 | ||
|
|
bd18dc7a62 | ||
|
|
9ccb597e6e | ||
|
|
38b3e04718 | ||
|
|
af9e865745 | ||
|
|
c47fcba5cc | ||
|
|
02501caa71 | ||
|
|
823eb068f0 | ||
|
|
954afd6409 | ||
|
|
9933e18ba5 | ||
|
|
1ff0ab1adf | ||
|
|
3bb9790229 | ||
|
|
0ad84be3ab | ||
|
|
35916af7bf | ||
|
|
72648286f2 | ||
|
|
42611085f4 | ||
|
|
f7e37c6b2c | ||
|
|
f44f21c5ad | ||
|
|
05200878f2 | ||
|
|
583163968d | ||
|
|
53c553db02 | ||
|
|
d65597c44f | ||
|
|
117c884b3e | ||
|
|
32315b1149 | ||
|
|
a9537e59cf | ||
|
|
2cd2aee11c | ||
|
|
5aa9671037 | ||
|
|
859cfc46d3 | ||
|
|
22927fa285 | ||
|
|
ae52adc0f5 | ||
|
|
dd1321a555 | ||
|
|
060a055d38 | ||
|
|
bb92766d5e | ||
|
|
aedb689e45 | ||
|
|
877c0a7c73 | ||
|
|
74f6e52c74 | ||
|
|
5bc5823ef2 | ||
|
|
45b0dd4887 | ||
|
|
18f622d007 | ||
|
|
ae7134a80f | ||
|
|
d06f7a869e | ||
|
|
be9c686d71 | ||
|
|
fcd4f36036 | ||
|
|
fbd8346edf | ||
|
|
4c5b59b453 | ||
|
|
03b6ed6f1a | ||
|
|
b5eaa757da | ||
|
|
ea46ac0196 | ||
|
|
88a0a2f9fc | ||
|
|
eb2d1f04c4 | ||
|
|
feb0dde706 | ||
|
|
973eac2b34 | ||
|
|
a16830f5ca | ||
|
|
315529eebf | ||
|
|
d3f72a036f | ||
|
|
e308a63f2b | ||
|
|
b0bcb4550e | ||
|
|
8b43f18f6a | ||
|
|
66bc855e4a | ||
|
|
6854d2885a | ||
|
|
21ff032cad | ||
|
|
c1dbc82338 | ||
|
|
4c7d3a37b4 | ||
|
|
658768f853 | ||
|
|
29a88e673f | ||
|
|
f2f6160aff | ||
|
|
27091f568f | ||
|
|
30f1b4e006 | ||
|
|
168d7a1652 | ||
|
|
bd0c35f64f | ||
|
|
f4c7e60b5a | ||
|
|
734de8129a | ||
|
|
1fd9ea7a27 | ||
|
|
c2ea68c39c | ||
|
|
e0db188195 | ||
|
|
1317791fed | ||
|
|
044e1b687f | ||
|
|
75b06a1cab | ||
|
|
57cf26c01c | ||
|
|
0ae32a3882 | ||
|
|
2f9bbbc84c | ||
|
|
5b2be09a6a | ||
|
|
bf001794b4 | ||
|
|
d5027c4c65 | ||
|
|
db13764b04 | ||
|
|
37022f7d7d | ||
|
|
ace2e5bb27 | ||
|
|
c809d572f7 | ||
|
|
a4a2623074 | ||
|
|
87e31965e5 | ||
|
|
012a796894 | ||
|
|
cc3caf2e5d | ||
|
|
1d239d409f | ||
|
|
71d77a62fd | ||
|
|
79f75ee861 | ||
|
|
f3ea825429 | ||
|
|
0d991a1420 | ||
|
|
985ebc2f77 | ||
|
|
17c17dd901 | ||
|
|
0004650b2f | ||
|
|
f3a3c68488 | ||
|
|
83ffce2a24 | ||
|
|
9fa1e77947 | ||
|
|
ac10329597 | ||
|
|
7b890e21d5 | ||
|
|
509f10f765 | ||
|
|
dd9cd53176 | ||
|
|
5e18c87bee | ||
|
|
2e0a771068 | ||
|
|
558b9e0b70 | ||
|
|
79cd1dd0d1 | ||
|
|
0d079fc593 | ||
|
|
30901462bc | ||
|
|
403801aac8 | ||
|
|
1dcfcb6250 | ||
|
|
b279ed4489 | ||
|
|
3cc1f3e9d7 | ||
|
|
23d9ed65ec | ||
|
|
a496debb5f | ||
|
|
d199260a63 | ||
|
|
353646e4bf | ||
|
|
b46c2c13cc | ||
|
|
a8caeb38ba | ||
|
|
6592ab6188 | ||
|
|
6dc552f015 | ||
|
|
8365ca000c | ||
|
|
dbb596b3c2 | ||
|
|
a947cc69de | ||
|
|
a3c0e46f1d | ||
|
|
7794be5993 | ||
|
|
a6e5f01ab9 | ||
|
|
c6ba5e4f70 | ||
|
|
093c95263f | ||
|
|
a4d068468d | ||
|
|
066d4c201d | ||
|
|
ae5ebf4bf9 | ||
|
|
c9a96df720 | ||
|
|
537f376ebd | ||
|
|
58f1cec916 | ||
|
|
4c3007ccc8 | ||
|
|
73cae89fc5 | ||
|
|
c3cb706f51 | ||
|
|
a703847130 | ||
|
|
4299ebcf1b | ||
|
|
a15d5e7d1e | ||
|
|
849d2c3d3e | ||
|
|
3e136baee2 | ||
|
|
f11c455b6b | ||
|
|
b0f7ce3f61 | ||
|
|
9c18bbd46e | ||
|
|
9c81d59833 | ||
|
|
51ee4a128a | ||
|
|
e5411cb1da | ||
|
|
289d403e0c | ||
|
|
0fe35ac161 | ||
|
|
ff1fa3d391 | ||
|
|
87f74b5ade | ||
|
|
4a21d0bfac | ||
|
|
b2e9b242ad | ||
|
|
acdd38743c | ||
|
|
c00c10301d | ||
|
|
d05438e034 | ||
|
|
d3cf65f1c0 | ||
|
|
960104b042 | ||
|
|
d78acd4205 | ||
|
|
dd4dca4473 | ||
|
|
05c9f83399 | ||
|
|
821edd00f7 | ||
|
|
068cad2207 | ||
|
|
9e068bdc90 | ||
|
|
e70bf6a379 | ||
|
|
2a0c7d1e56 | ||
|
|
32a4204609 | ||
|
|
74b3b00ea5 | ||
|
|
01fba0b722 | ||
|
|
fa290752c9 | ||
|
|
4ed769271d | ||
|
|
7f1e7615cf | ||
|
|
2d4dc568fb | ||
|
|
02eefcd00f | ||
|
|
e742342dd8 | ||
|
|
b812070ae1 | ||
|
|
70dada90b2 | ||
|
|
b3d2e29e28 | ||
|
|
bb0f31f814 | ||
|
|
c0c477a3b7 | ||
|
|
a55c735d13 | ||
|
|
86bbfbe254 | ||
|
|
ba270000b2 | ||
|
|
5fceb9898f | ||
|
|
1cf28e0dd5 | ||
|
|
ffe290d56d | ||
|
|
7e8344cd4e | ||
|
|
3fc66ce202 | ||
|
|
167b9cfa42 | ||
|
|
00070d06b6 | ||
|
|
9520898032 | ||
|
|
71ee7ac019 | ||
|
|
e77d7a42f5 | ||
|
|
99291c2576 | ||
|
|
e9bd4a4dc5 | ||
|
|
1b95ce330a | ||
|
|
26641a4584 | ||
|
|
27140c04c9 | ||
|
|
0bf3c64ceb | ||
|
|
13565a0904 | ||
|
|
642b7ae5ba | ||
|
|
6776c49750 | ||
|
|
1189610b42 | ||
|
|
839cddfe7f | ||
|
|
86e2db388e | ||
|
|
608b078065 | ||
|
|
74d2c07ea0 | ||
|
|
a84cc07aa2 | ||
|
|
d2f2028f55 | ||
|
|
53e2aeff3f | ||
|
|
80aebe3869 | ||
|
|
7f0e2bcb9e | ||
|
|
cc2b0a610f | ||
|
|
d7a2883b5c | ||
|
|
6a76583e1b | ||
|
|
c161d6272a | ||
|
|
62cdfc9680 | ||
|
|
ff5826ec21 | ||
|
|
69ec80831c | ||
|
|
b80bb138e2 | ||
|
|
0fb114967a | ||
|
|
e9d55adfff | ||
|
|
ba1ef42355 | ||
|
|
c23bb13187 | ||
|
|
330ff5b9d0 | ||
|
|
132c399e32 | ||
|
|
c5c2a1bbf4 | ||
|
|
3ce5b43126 | ||
|
|
423c9c7b9c | ||
|
|
45b05fc823 | ||
|
|
808fc51966 | ||
|
|
bb4f415ae1 | ||
|
|
f6f7fb3b8f | ||
|
|
d22d97ed65 | ||
|
|
3a2881b350 | ||
|
|
0d59377284 | ||
|
|
b3016dffca | ||
|
|
32601826c1 | ||
|
|
f5aebd7044 | ||
|
|
457d0977b6 | ||
|
|
befa3f82ed | ||
|
|
56ca068a2c | ||
|
|
d09b447574 | ||
|
|
e5939e3ca5 | ||
|
|
2bd45883ce | ||
|
|
d3b47776c3 | ||
|
|
c1d9763945 | ||
|
|
83126c3ec4 | ||
|
|
c4f08715ed | ||
|
|
5ad7e2f128 | ||
|
|
0299024804 | ||
|
|
aaa4727bc0 | ||
|
|
f69760808a | ||
|
|
9598ad7a73 | ||
|
|
bf00d844dd | ||
|
|
87110408ef | ||
|
|
546e40c1ff | ||
|
|
8306b5d534 | ||
|
|
34897247dd | ||
|
|
9037973ced | ||
|
|
672865c062 | ||
|
|
96f10bebd4 | ||
|
|
8aed23ca93 | ||
|
|
19f18fe032 | ||
|
|
9bf4edecdb | ||
|
|
af6feaf735 | ||
|
|
289ddd673b | ||
|
|
0aeff4a8ae | ||
|
|
f15daa9a0f | ||
|
|
c7da14f52e | ||
|
|
23c27aa781 | ||
|
|
e5671a1fcc | ||
|
|
3b5c2b830e | ||
|
|
7fc7d79554 | ||
|
|
417ac32f54 | ||
|
|
713b01fc7d | ||
|
|
8ed80d3feb | ||
|
|
b59b07e93d | ||
|
|
1f2b09e704 | ||
|
|
6b3d39fbd7 | ||
|
|
98ed6c3fcb | ||
|
|
faa09134d5 | ||
|
|
b271e19dc8 | ||
|
|
762fa7150e | ||
|
|
db6f8dbff8 | ||
|
|
af25c83aa2 | ||
|
|
cca59a33b9 | ||
|
|
4246d2a91b | ||
|
|
b52476855f | ||
|
|
d5e7dbc762 | ||
|
|
af8756218e | ||
|
|
ce271d2288 | ||
|
|
60dd2dd800 | ||
|
|
52880e94a9 | ||
|
|
974cec75be | ||
|
|
3baa699d79 | ||
|
|
3423a7aa5d | ||
|
|
60f7282774 | ||
|
|
980a1f4c5a | ||
|
|
3cb0c1b325 | ||
|
|
752ae51f46 | ||
|
|
c4c9f71b01 | ||
|
|
7a85fa5c61 | ||
|
|
e9a6b55ba4 | ||
|
|
8e7a3a9347 | ||
|
|
d6344093b6 | ||
|
|
34211dafef | ||
|
|
e140b2f663 | ||
|
|
d2deea9502 | ||
|
|
31bfb53dfb | ||
|
|
b6ced23649 | ||
|
|
6af03fdfca | ||
|
|
88684c9725 | ||
|
|
9ab641c19a | ||
|
|
c8740e7331 | ||
|
|
6aa9bd7e8c | ||
|
|
d6bf9689ff | ||
|
|
1876fb7431 | ||
|
|
50a5394165 | ||
|
|
b54a572da6 | ||
|
|
1f934eaefa | ||
|
|
87d75fd718 | ||
|
|
d22e39b3f3 | ||
|
|
add5b856dc | ||
|
|
2f19a21b5f | ||
|
|
ee9db04c08 | ||
|
|
68c51c4549 | ||
|
|
762bf413e8 | ||
|
|
6159f5e4ee | ||
|
|
b70444acac | ||
|
|
dd53cf4e58 | ||
|
|
23eaab0757 | ||
|
|
c662023819 | ||
|
|
3d1c106759 | ||
|
|
90e2dca36b | ||
|
|
79b2933be7 | ||
|
|
eb16c925d2 | ||
|
|
1bef528fde | ||
|
|
bcf579e7d7 | ||
|
|
bf7cbe141d | ||
|
|
fce4295e2a | ||
|
|
fc95069421 | ||
|
|
77ac215b76 | ||
|
|
85397732c8 | ||
|
|
49a81c10db | ||
|
|
b742ffcafd | ||
|
|
55ece20d70 | ||
|
|
261a7f278b | ||
|
|
e6605d7ac9 | ||
|
|
20247493c8 | ||
|
|
cfea740511 | ||
|
|
9e48010ee6 | ||
|
|
ff4b388877 | ||
|
|
5195e2ac74 | ||
|
|
f958b16343 | ||
|
|
18e3adde11 | ||
|
|
9476d26972 | ||
|
|
8cfe36be68 | ||
|
|
6e8514e08c | ||
|
|
c67a6b0c9e | ||
|
|
13199bb3f7 | ||
|
|
5fd0b46756 | ||
|
|
c90315679f | ||
|
|
a9be915f87 | ||
|
|
57e7eb9e05 | ||
|
|
785e96036a | ||
|
|
98979a2271 | ||
|
|
eb91b6ea6d | ||
|
|
9af44e15b4 | ||
|
|
4edaebe054 | ||
|
|
fe92c1b30f | ||
|
|
e9d6f46997 | ||
|
|
9b743d7afe | ||
|
|
e1feb8bcd5 | ||
|
|
c94db7e9b8 | ||
|
|
dfc35d00da | ||
|
|
8b2322ef6c | ||
|
|
9bd29228b0 | ||
|
|
3437b41114 | ||
|
|
76a1423e72 | ||
|
|
b99145e863 | ||
|
|
e2ec5469a7 | ||
|
|
9920578ca2 | ||
|
|
be1ca57515 | ||
|
|
7c2ce513df | ||
|
|
1b6dbbc288 | ||
|
|
138515da02 | ||
|
|
5820d03bb5 | ||
|
|
4999e9d944 | ||
|
|
3ef528cdf6 | ||
|
|
1571b70716 | ||
|
|
16181dd1b9 | ||
|
|
f7d9a3cd17 | ||
|
|
1e6d91b50f | ||
|
|
73bdba5076 | ||
|
|
c67540b728 | ||
|
|
3df7ec4692 | ||
|
|
bd94e27af6 | ||
|
|
9a37542158 | ||
|
|
c71b7de363 | ||
|
|
ea8c28a205 | ||
|
|
f448c66c17 | ||
|
|
3c850ef195 | ||
|
|
9afb59ea87 | ||
|
|
b3c6c0fc9b | ||
|
|
ae758a114a | ||
|
|
01e1af1fbd | ||
|
|
3759019cbc | ||
|
|
9cff56c1a4 | ||
|
|
511fb8de6a | ||
|
|
fd36ede27b | ||
|
|
a904263ed5 | ||
|
|
02aae58e71 | ||
|
|
7495b6c2c4 | ||
|
|
aa1e2188fb | ||
|
|
8c3c401efb | ||
|
|
5cd37a02c7 | ||
|
|
2bb1670428 | ||
|
|
485e8444fe | ||
|
|
5395ca5caf | ||
|
|
c416819f0a | ||
|
|
0a1e062caf | ||
|
|
85230b5123 | ||
|
|
a33cff7406 | ||
|
|
006cddccd9 | ||
|
|
67867cc127 | ||
|
|
f0bb00f977 | ||
|
|
54290886ea | ||
|
|
816b26475a | ||
|
|
46d7d4e587 | ||
|
|
263f94418d | ||
|
|
f990863bb2 | ||
|
|
d91cd53375 | ||
|
|
6a9fdd6c77 | ||
|
|
f1185fcade | ||
|
|
0cef11266a | ||
|
|
653fc1880f | ||
|
|
cbf84922bb | ||
|
|
0cad88f1ab | ||
|
|
1b7f8ff648 | ||
|
|
7097cb335d | ||
|
|
877c660ba9 | ||
|
|
04f6461cb5 | ||
|
|
6566973f3e | ||
|
|
8e014ae7c6 | ||
|
|
929c706fc0 | ||
|
|
debf52ee88 | ||
|
|
d993430c01 | ||
|
|
f337b835d0 | ||
|
|
f8c44feab8 | ||
|
|
0329c40265 | ||
|
|
1fde4b9f16 | ||
|
|
e58c48aa70 | ||
|
|
96ee1e3ed2 | ||
|
|
60b66b5e7f | ||
|
|
db1eb19ef0 | ||
|
|
13f1309857 | ||
|
|
4ee96637de | ||
|
|
dae8fbc9b5 | ||
|
|
4abd131b8a | ||
|
|
9b0d11963c | ||
|
|
ed3b27475e | ||
|
|
9dadb92d8d | ||
|
|
7d0ae17ddd | ||
|
|
fe8600d569 | ||
|
|
1433903fac | ||
|
|
ab636232ff | ||
|
|
76f3a523c1 | ||
|
|
b53197d948 | ||
|
|
0b5e057e4e | ||
|
|
38f58ae5f9 | ||
|
|
875fd10b50 | ||
|
|
041aaea0b9 | ||
|
|
e2c0501e3d | ||
|
|
d841ae5a60 | ||
|
|
d139d23c21 | ||
|
|
5e65001e37 | ||
|
|
e70656b5a3 | ||
|
|
b30705fa31 | ||
|
|
26c6078693 | ||
|
|
9a68c48456 | ||
|
|
6185556b9b | ||
|
|
2828fdf2c6 | ||
|
|
b598729f28 | ||
|
|
86d3067713 | ||
|
|
38e5b4da82 | ||
|
|
e1288bfd61 | ||
|
|
cde45111f6 | ||
|
|
947bd57b99 | ||
|
|
e800d048f2 | ||
|
|
a788313974 | ||
|
|
3d2492a045 | ||
|
|
9fe76eb527 | ||
|
|
6fabb39788 | ||
|
|
c403f4f3a1 | ||
|
|
5f6ae20f96 | ||
|
|
b879cbed32 | ||
|
|
602aa74bd9 | ||
|
|
9db616e965 | ||
|
|
163c8161fc | ||
|
|
2619059f58 | ||
|
|
9e7033ce54 | ||
|
|
bc653494aa | ||
|
|
bb84a609a0 | ||
|
|
53b1b162b2 | ||
|
|
70e56d748a | ||
|
|
9428a13f7a | ||
|
|
81ded2b247 | ||
|
|
1d2eed2b46 | ||
|
|
a55a70266b | ||
|
|
fd4d8ea2e8 | ||
|
|
4e4e865497 | ||
|
|
3cef7ff545 | ||
|
|
6e07067d94 | ||
|
|
509596ff76 | ||
|
|
aa4bb92a8f | ||
|
|
0dd3f7ef46 | ||
|
|
a54237e8e2 | ||
|
|
104d98b765 | ||
|
|
75448d5e5a | ||
|
|
371dcf8ab9 | ||
|
|
da316fdcfd | ||
|
|
ba083fff70 | ||
|
|
30d5fedb11 | ||
|
|
187a149716 | ||
|
|
28e691122f | ||
|
|
5fef369e91 | ||
|
|
dcac233296 | ||
|
|
b90a719972 | ||
|
|
d42d8965e6 | ||
|
|
ab86c5129e | ||
|
|
5b0c32084a | ||
|
|
c0ad778c90 | ||
|
|
a6359f0756 | ||
|
|
7500fdd380 | ||
|
|
0fc0a00f47 | ||
|
|
05bcfdc16e | ||
|
|
dca50a4e45 | ||
|
|
e16fa2dc31 | ||
|
|
dc120a06ca | ||
|
|
05cf33ffb2 | ||
|
|
0a7a8e49fe | ||
|
|
a1742f71e0 | ||
|
|
b1e727f269 | ||
|
|
dbde6abc8c | ||
|
|
a13256cf39 | ||
|
|
1197e11f58 | ||
|
|
743fc4aa41 | ||
|
|
71644e255d | ||
|
|
7f32b99284 | ||
|
|
746aa4cb96 | ||
|
|
d40dc06171 | ||
|
|
7354f69dc3 | ||
|
|
815dd6b4b6 | ||
|
|
33c843e5d8 | ||
|
|
2473c4109e | ||
|
|
171a8670a4 | ||
|
|
027e3425bb | ||
|
|
138dcf3d2a | ||
|
|
8231964023 | ||
|
|
e9a8a97982 | ||
|
|
7dece286ec | ||
|
|
dc32172d8c | ||
|
|
22c5485b3b | ||
|
|
73894ade73 | ||
|
|
7a7c8c02de | ||
|
|
72dc526724 | ||
|
|
7a48b32bd5 | ||
|
|
db58520afe | ||
|
|
1ec9dfea7f | ||
|
|
e36f081d96 | ||
|
|
cfcd41fc7e | ||
|
|
60cac291ff | ||
|
|
c3cfb7ae2f | ||
|
|
067ba8ea85 | ||
|
|
14a4398a14 | ||
|
|
ff759c31b2 | ||
|
|
854198f215 | ||
|
|
6fcfa3d984 | ||
|
|
1e1ef7f94b | ||
|
|
b47f627508 | ||
|
|
0da8f45084 | ||
|
|
c147ec1067 | ||
|
|
e4149fa55e | ||
|
|
ccb0e5278d | ||
|
|
cb83f3592b | ||
|
|
342af990f6 | ||
|
|
737e46a90e | ||
|
|
b7e67d4e2a | ||
|
|
4dc9ed6438 | ||
|
|
e1f2a7dcf7 | ||
|
|
70ad285e09 | ||
|
|
d2459016f1 | ||
|
|
c6ec5cf645 | ||
|
|
1881dde11f | ||
|
|
b06bd19bc9 | ||
|
|
b93a591401 | ||
|
|
7ff9dd5a57 | ||
|
|
96397c24b4 | ||
|
|
a9bc6502cb | ||
|
|
4f4eb773fc | ||
|
|
48e00a0ecc | ||
|
|
f8593255ac | ||
|
|
598d5aab10 | ||
|
|
26cb81a720 | ||
|
|
20c742d43d | ||
|
|
1b1f54feb0 | ||
|
|
6da1f892ce | ||
|
|
e243a914e9 | ||
|
|
df3ba86977 | ||
|
|
91646a809b | ||
|
|
2db170a3ae | ||
|
|
d9ca47914d | ||
|
|
657f27822c | ||
|
|
ed3d8b984e | ||
|
|
ed1970b6d8 | ||
|
|
d374960c35 | ||
|
|
3feac9f0b4 | ||
|
|
dc6fde9f77 | ||
|
|
be3a709335 | ||
|
|
883bdcd845 | ||
|
|
d5a1187e13 | ||
|
|
d413ed2de0 | ||
|
|
ac0ae00015 | ||
|
|
325871f7c5 | ||
|
|
5662661326 | ||
|
|
864b5514be | ||
|
|
2044d3eb6b | ||
|
|
577b262418 | ||
|
|
d6c7ab0735 | ||
|
|
15884597b4 | ||
|
|
4fd32155dc | ||
|
|
c9acda1b6d | ||
|
|
29b5830e19 | ||
|
|
3d95212023 | ||
|
|
2179b193d2 | ||
|
|
89a5a9f42f | ||
|
|
cd69e00451 | ||
|
|
fc66c3e689 | ||
|
|
67ea0cfe73 | ||
|
|
406ac81684 | ||
|
|
c1f16a5b6a | ||
|
|
236d24c79b | ||
|
|
b55cf7c0d8 | ||
|
|
87d6105159 | ||
|
|
194f07d48e | ||
|
|
0c48f53ab1 | ||
|
|
6aba9064a7 | ||
|
|
a2f87c8bd5 | ||
|
|
67361113af | ||
|
|
3d2a66023d | ||
|
|
d99e405f10 | ||
|
|
d5a8f234f8 | ||
|
|
018bd8a767 | ||
|
|
e1e92d944a | ||
|
|
5dd1720b88 | ||
|
|
e84903d2dd | ||
|
|
ca1a292fb2 | ||
|
|
62ba1f0f75 | ||
|
|
5ca3ca5289 | ||
|
|
ac5d37a9e3 | ||
|
|
23732dd087 | ||
|
|
5aae59cdda | ||
|
|
3563c20997 | ||
|
|
14ac034c0b | ||
|
|
cd5e40a1f5 | ||
|
|
72cc188efe | ||
|
|
2d50da84c8 | ||
|
|
dd6f88a1cd | ||
|
|
ac5d9d99f1 | ||
|
|
5ff595b268 | ||
|
|
3cebd975a8 | ||
|
|
dac0dfb8f9 | ||
|
|
77cf819ab4 | ||
|
|
760b1f3f85 | ||
|
|
db8e203c36 | ||
|
|
1e9a014ce7 | ||
|
|
e1ce353069 | ||
|
|
2d97aa2e59 | ||
|
|
584ce6d416 | ||
|
|
61c1847d75 | ||
|
|
b922d135c5 | ||
|
|
aedf659144 | ||
|
|
ca3ec5e94c | ||
|
|
e605d4c0df | ||
|
|
74377a93d8 | ||
|
|
d9d286d94e | ||
|
|
8e87ebd50b | ||
|
|
87750805ae | ||
|
|
9908cf5a29 | ||
|
|
0657b16002 | ||
|
|
703ba3ef6e | ||
|
|
3a64b675bb | ||
|
|
cfe9178301 | ||
|
|
b3d94e9bcf | ||
|
|
8aac4bf55f | ||
|
|
ca9c244182 | ||
|
|
c4f81f55d1 | ||
|
|
8397ed52ce | ||
|
|
92859aa748 | ||
|
|
1fcc425779 | ||
|
|
52bfe0310a | ||
|
|
1a9a36cb4c | ||
|
|
3f12ff2830 | ||
|
|
15ba2dd297 | ||
|
|
b9dd371676 | ||
|
|
0f47842b5f | ||
|
|
49895a7d7f | ||
|
|
520d893fd2 | ||
|
|
e25d439b9b | ||
|
|
7103477598 | ||
|
|
b0379e8945 | ||
|
|
4649561886 | ||
|
|
1cfb83ab02 | ||
|
|
b7eb130a63 | ||
|
|
c2a5f85a02 | ||
|
|
b9f8f55a30 | ||
|
|
5e05e50049 | ||
|
|
cba69a84d3 | ||
|
|
8044bd75df | ||
|
|
9b82ba22a3 | ||
|
|
ac3061a232 | ||
|
|
4278e9c474 | ||
|
|
3be95042a3 | ||
|
|
b1f3b440f7 | ||
|
|
55b4ce8326 | ||
|
|
6c5dd38dbf | ||
|
|
3f9f554b4c | ||
|
|
2450dcf4c2 | ||
|
|
7718da93a5 | ||
|
|
ef01223d9d | ||
|
|
d299f94518 | ||
|
|
375260d701 | ||
|
|
dc49a59111 | ||
|
|
13dea41c97 | ||
|
|
3e4f8e7041 | ||
|
|
f3860a077e | ||
|
|
cee429abdb | ||
|
|
80b86189d0 | ||
|
|
4ecc64e478 | ||
|
|
46e1552f1e | ||
|
|
34183aab64 | ||
|
|
e32facf3e6 | ||
|
|
571d721925 | ||
|
|
f1e91ab11a | ||
|
|
a5b289d290 | ||
|
|
0925f7f0a2 | ||
|
|
bf7f1d43c0 | ||
|
|
e0eda79a91 | ||
|
|
9334540e1e | ||
|
|
f67516f696 | ||
|
|
5663378bf2 | ||
|
|
45c4d1c623 | ||
|
|
7129b2822b | ||
|
|
65497862ea | ||
|
|
e2c3b625db | ||
|
|
acfbcf1cf4 | ||
|
|
c1327fd8aa | ||
|
|
706bb12273 | ||
|
|
323f027a9d | ||
|
|
248d8e09a9 | ||
|
|
716b1be234 | ||
|
|
8f5f1a22ee | ||
|
|
f9b740b683 | ||
|
|
2f0cef6ab9 | ||
|
|
8813b0cf1c | ||
|
|
fd4026f27a | ||
|
|
bbaabeef38 | ||
|
|
093b736a3b | ||
|
|
70cc6a35d7 | ||
|
|
5792c2bae6 |
56
.github/workflows/auth-internal-release.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: "Internal release (auth mobile)"
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Allow manually running the action
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.24.3"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: auth
|
||||
|
||||
steps:
|
||||
- name: Checkout code and submodules
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup JDK 17
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 17
|
||||
|
||||
- name: Install Flutter ${{ env.FLUTTER_VERSION }}
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Setup keys
|
||||
uses: timheuer/base64-to-file@v1
|
||||
with:
|
||||
fileName: "keystore/ente_auth_key.jks"
|
||||
encodedString: ${{ secrets.SIGNING_KEY }}
|
||||
|
||||
- name: Build PlayStore AAB
|
||||
run: |
|
||||
flutter build appbundle --release --flavor playstore --dart-define=app.flavor=playstore
|
||||
env:
|
||||
SIGNING_KEY_PATH: "/home/runner/work/_temp/keystore/ente_auth_key.jks"
|
||||
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
|
||||
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
|
||||
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
|
||||
|
||||
- name: Upload AAB to PlayStore
|
||||
uses: r0adkll/upload-google-play@v1
|
||||
with:
|
||||
serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
|
||||
packageName: io.ente.auth
|
||||
releaseFiles: auth/build/app/outputs/bundle/playstoreRelease/app-playstore-release.aab
|
||||
track: internal
|
||||
7
.github/workflows/auth-lint.yml
vendored
@@ -1,15 +1,14 @@
|
||||
name: "Lint (auth)"
|
||||
|
||||
on:
|
||||
# Run on every push to a branch other than main that changes auth/
|
||||
push:
|
||||
branches-ignore: [main]
|
||||
# Run on every pull request (open or push to it) that changes auth/
|
||||
pull_request:
|
||||
paths:
|
||||
- "auth/**"
|
||||
- ".github/workflows/auth-lint.yml"
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.24.0"
|
||||
FLUTTER_VERSION: "3.24.3"
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
|
||||
2
.github/workflows/auth-release.yml
vendored
@@ -29,7 +29,7 @@ on:
|
||||
- "auth-v*"
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.24.0"
|
||||
FLUTTER_VERSION: "3.24.3"
|
||||
|
||||
jobs:
|
||||
build-ubuntu:
|
||||
|
||||
5
.github/workflows/desktop-lint.yml
vendored
@@ -1,9 +1,8 @@
|
||||
name: "Lint (desktop)"
|
||||
|
||||
on:
|
||||
# Run on every push to a branch other than main that changes desktop/
|
||||
push:
|
||||
branches-ignore: [main]
|
||||
# Run on every pull request (open or push to it) that changes desktop/
|
||||
pull_request:
|
||||
paths:
|
||||
- "desktop/**"
|
||||
- ".github/workflows/desktop-lint.yml"
|
||||
|
||||
5
.github/workflows/docs-verify-build.yml
vendored
@@ -4,9 +4,8 @@ name: "Verify build (docs)"
|
||||
# succeeding before we merge the PR into main.
|
||||
|
||||
on:
|
||||
# Run on every push to a branch other than main that changes docs/
|
||||
push:
|
||||
branches-ignore: [main]
|
||||
# Run on every pull request (open or push to it) that changes docs/
|
||||
pull_request:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- ".github/workflows/docs-verify-build.yml"
|
||||
|
||||
5
.github/workflows/infra-lint-staff.yml
vendored
@@ -1,9 +1,8 @@
|
||||
name: "Lint (staff)"
|
||||
|
||||
on:
|
||||
# Run on every push to a branch other than main that changes infra/staff/
|
||||
push:
|
||||
branches-ignore: [main]
|
||||
# Run on every pull request (open or push to it) that changes infra/staff/
|
||||
pull_request:
|
||||
paths:
|
||||
- "infra/staff/**"
|
||||
- ".github/workflows/infra-deploy-staff.yml"
|
||||
|
||||
1
.github/workflows/mobile-crowdin-sync.yml
vendored
@@ -26,7 +26,6 @@ jobs:
|
||||
download_translations: true
|
||||
localization_branch_name: translations/mobile
|
||||
create_pull_request: true
|
||||
skip_untranslated_strings: true
|
||||
pull_request_title: "[mobile] New translations"
|
||||
pull_request_body: "New translations from [Crowdin](https://crowdin.com/project/ente-photos-app)"
|
||||
pull_request_base_branch_name: "main"
|
||||
|
||||
@@ -4,7 +4,7 @@ on:
|
||||
workflow_dispatch: # Allow manually running the action
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.22.2"
|
||||
FLUTTER_VERSION: "3.24.3"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
7
.github/workflows/mobile-lint.yml
vendored
@@ -1,16 +1,15 @@
|
||||
name: "Lint (mobile)"
|
||||
|
||||
on:
|
||||
# Run on every push to a branch other than main that changes mobile/
|
||||
push:
|
||||
branches-ignore: [main, f-droid]
|
||||
# Run on every pull request (open or push to it) that changes mobile/
|
||||
pull_request:
|
||||
paths:
|
||||
- "mobile/**"
|
||||
- ".github/workflows/mobile-lint.yml"
|
||||
|
||||
env:
|
||||
|
||||
FLUTTER_VERSION: "3.22.2"
|
||||
FLUTTER_VERSION: "3.24.3"
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
|
||||
2
.github/workflows/mobile-release.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
- "photos-v*"
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.22.2"
|
||||
FLUTTER_VERSION: "3.24.3"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
5
.github/workflows/server-lint.yml
vendored
@@ -1,9 +1,8 @@
|
||||
name: "Lint (server)"
|
||||
|
||||
on:
|
||||
# Run on every push to a branch other than main that changes server/
|
||||
push:
|
||||
branches-ignore: [main]
|
||||
# Run on every pull request (open or push to it) that changes server/
|
||||
pull_request:
|
||||
paths:
|
||||
- "server/**"
|
||||
- ".github/workflows/server-lint.yml"
|
||||
|
||||
10
.github/workflows/web-lint.yml
vendored
@@ -1,13 +1,17 @@
|
||||
name: "Lint (web)"
|
||||
|
||||
on:
|
||||
# Run on every push to a branch other than main that changes web/
|
||||
push:
|
||||
branches-ignore: [main]
|
||||
# Run on every pull request (open or push to it) that changes web/
|
||||
pull_request:
|
||||
paths:
|
||||
- "web/**"
|
||||
- ".github/workflows/web-lint.yml"
|
||||
|
||||
# Cancel in-progress lint runs when a new commit is pushed.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -57,7 +57,7 @@ android {
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 33
|
||||
targetSdkVersion 34
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -1 +1 @@
|
||||
Auth is a FOSS authenticator app that provides end-to-end encrypted backups for your 2FA secrets.
|
||||
Auth is a FOSS authenticator app that provides end-to-end encrypted backups for your 2FA secrets.
|
||||
@@ -17,6 +17,9 @@
|
||||
"title": "airtm",
|
||||
"hex": "000000"
|
||||
},
|
||||
{
|
||||
"title": "Amazon"
|
||||
},
|
||||
{
|
||||
"title": "Anycoin Direct",
|
||||
"slug": "anycoindirect"
|
||||
@@ -24,6 +27,27 @@
|
||||
{
|
||||
"title": "AscendEX"
|
||||
},
|
||||
{
|
||||
"title": "Battle.net",
|
||||
"slug": "battlenet",
|
||||
"altNames": [
|
||||
"Battle net",
|
||||
"Blizzard"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Bethesda",
|
||||
"altNames": [
|
||||
"Bethesda Softworks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "BinanceUS",
|
||||
"slug": "binance_us",
|
||||
"altNames": [
|
||||
"Binance US"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Bitfinex"
|
||||
},
|
||||
@@ -31,12 +55,12 @@
|
||||
"title": "bitget"
|
||||
},
|
||||
{
|
||||
"titile":"bitget wallet",
|
||||
"slug":"bitget_wallet"
|
||||
"title": "bitget wallet",
|
||||
"slug": "bitget_wallet"
|
||||
},
|
||||
{
|
||||
"title": "Bitmart",
|
||||
"hex":"000000"
|
||||
"hex": "000000"
|
||||
},
|
||||
{
|
||||
"title": "BitMEX"
|
||||
@@ -51,8 +75,7 @@
|
||||
"title": "Bitstamp"
|
||||
},
|
||||
{
|
||||
"title": "Bitvavo",
|
||||
"hex": "0051FF"
|
||||
"title": "Bitvavo"
|
||||
},
|
||||
{
|
||||
"title": "Bitwarden"
|
||||
@@ -70,27 +93,24 @@
|
||||
"blockchain.com",
|
||||
"blockchain.com Wallet",
|
||||
"blockchain.com Exchange"
|
||||
],
|
||||
"slug": "blockchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "BorgBase",
|
||||
"altNames": [
|
||||
"borg"
|
||||
],
|
||||
"slug": "BorgBase"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Booking",
|
||||
"slug": "booking",
|
||||
"altNames":[
|
||||
"altNames": [
|
||||
"Booking.com"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Brave Creators",
|
||||
"slug": "brave_creators",
|
||||
"altNames":[
|
||||
"altNames": [
|
||||
"Brave",
|
||||
"Brave Rewards",
|
||||
"Brave Browser"
|
||||
@@ -99,6 +119,9 @@
|
||||
{
|
||||
"title": "Bybit"
|
||||
},
|
||||
{
|
||||
"title": "Capacities"
|
||||
},
|
||||
{
|
||||
"title": "CERN"
|
||||
},
|
||||
@@ -110,15 +133,11 @@
|
||||
"slug": "cih",
|
||||
"hex": "D14633"
|
||||
},
|
||||
{
|
||||
"title": "Cloudflare"
|
||||
},
|
||||
{
|
||||
"title": "CloudAMQP"
|
||||
},
|
||||
{
|
||||
"title": "ConfigCat",
|
||||
"slug": "configcat"
|
||||
"title": "Cloudflare"
|
||||
},
|
||||
{
|
||||
"title": "CoinDCX"
|
||||
@@ -128,8 +147,7 @@
|
||||
},
|
||||
{
|
||||
"title": "Control D",
|
||||
"slug": "controld",
|
||||
"hex": "5FD800"
|
||||
"slug": "controld"
|
||||
},
|
||||
{
|
||||
"title": "Crowdpear"
|
||||
@@ -139,7 +157,6 @@
|
||||
"slug": "crypto",
|
||||
"altNames": [
|
||||
"crypto",
|
||||
"Crypto.com",
|
||||
"Crypto com"
|
||||
]
|
||||
},
|
||||
@@ -147,8 +164,7 @@
|
||||
"title": "DCS",
|
||||
"altNames": [
|
||||
"Digital Combat Simulator"
|
||||
],
|
||||
"slug": "dcs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "DEGIRO"
|
||||
@@ -173,16 +189,22 @@
|
||||
"slug": "dusnet"
|
||||
},
|
||||
{
|
||||
"title":"ecitizen kenya",
|
||||
"slug":"ecitizen_kenya"
|
||||
"title": "ecitizen kenya",
|
||||
"slug": "ecitizen_kenya"
|
||||
},
|
||||
{
|
||||
"title": "ecloud",
|
||||
"altNames": [
|
||||
"Murena"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "ente",
|
||||
"hex": "1DB954"
|
||||
},
|
||||
{
|
||||
"title": "enom"
|
||||
},
|
||||
"title": "enom"
|
||||
},
|
||||
{
|
||||
"title": "Epic Games",
|
||||
"slug": "epic_games",
|
||||
@@ -218,10 +240,17 @@
|
||||
},
|
||||
{
|
||||
"title": "Gosuslugi",
|
||||
"slug": "Gosuslugi",
|
||||
"altNames": [
|
||||
"Госуслуги"
|
||||
],
|
||||
"slug": "Gosuslugi"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "GOV.UK",
|
||||
"slug": "gov_uk",
|
||||
"altNames": [
|
||||
"Government Gateway"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Habbo"
|
||||
@@ -240,16 +269,13 @@
|
||||
"title": "HuggingFace",
|
||||
"altNames": [
|
||||
"Hugging Face"
|
||||
],
|
||||
"slug": "huggingface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "IceDrive",
|
||||
"slug": "Icedrive"
|
||||
"title": "IceDrive"
|
||||
},
|
||||
{
|
||||
"titile": "Infomaniak",
|
||||
"slug": "infomaniak"
|
||||
"title": "Infomaniak"
|
||||
},
|
||||
{
|
||||
"title": "ING"
|
||||
@@ -270,8 +296,7 @@
|
||||
"hex": "000000"
|
||||
},
|
||||
{
|
||||
"title": "IVPN",
|
||||
"slug": "IVPN"
|
||||
"title": "IVPN"
|
||||
},
|
||||
{
|
||||
"title": "Jagex",
|
||||
@@ -281,8 +306,7 @@
|
||||
"title": "Kagi"
|
||||
},
|
||||
{
|
||||
"title": "Kick",
|
||||
"hex": "53FC19"
|
||||
"title": "Kick"
|
||||
},
|
||||
{
|
||||
"title": "Kite"
|
||||
@@ -295,15 +319,13 @@
|
||||
"color": "00CC00"
|
||||
},
|
||||
{
|
||||
"title": "Kraken",
|
||||
"hex": "5848D5"
|
||||
"title": "Kraken"
|
||||
},
|
||||
{
|
||||
"title": "Kronos"
|
||||
},
|
||||
{
|
||||
"title": "KuCoin",
|
||||
"hex": "01BC8D"
|
||||
"title": "KuCoin"
|
||||
},
|
||||
{
|
||||
"title": "La Poste",
|
||||
@@ -333,7 +355,6 @@
|
||||
"mathstodon",
|
||||
"fosstodon"
|
||||
],
|
||||
"slug": "mastodon",
|
||||
"hex": "6364FF"
|
||||
},
|
||||
{
|
||||
@@ -364,13 +385,6 @@
|
||||
{
|
||||
"title": "Mozilla"
|
||||
},
|
||||
{
|
||||
"title": "Murena",
|
||||
"altNames": [
|
||||
"eCloud"
|
||||
],
|
||||
"slug": "ecloud"
|
||||
},
|
||||
{
|
||||
"title": "MyFRITZ!Net",
|
||||
"slug": "myfritz",
|
||||
@@ -406,6 +420,12 @@
|
||||
{
|
||||
"title": "NextDNS"
|
||||
},
|
||||
{
|
||||
"title": "Newton",
|
||||
"altNames": [
|
||||
"Newton Crypto"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "ngrok",
|
||||
"hex": "858585"
|
||||
@@ -420,8 +440,7 @@
|
||||
"title": "Notion"
|
||||
},
|
||||
{
|
||||
"title": "NuCommunity",
|
||||
"slug": "nucommunity"
|
||||
"title": "NuCommunity"
|
||||
},
|
||||
{
|
||||
"title": "NVIDIA"
|
||||
@@ -430,16 +449,17 @@
|
||||
"title": "Odido"
|
||||
},
|
||||
{
|
||||
"titile": "OpenObserve",
|
||||
"title": "OpenObserve",
|
||||
"slug": "open_observe",
|
||||
"altNames":[
|
||||
"altNames": [
|
||||
"openobserve.ai",
|
||||
"openobserve ai"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "okx",
|
||||
"hex": "000000" },
|
||||
"hex": "000000"
|
||||
},
|
||||
{
|
||||
"title": "Parsec"
|
||||
},
|
||||
@@ -447,16 +467,13 @@
|
||||
"title": "PayPal"
|
||||
},
|
||||
{
|
||||
"title": "pCloud",
|
||||
"slug": "pCloud"
|
||||
"title": "pCloud"
|
||||
},
|
||||
{
|
||||
"title": "Peerberry",
|
||||
"hex": "03E5A5"
|
||||
"title": "Peerberry"
|
||||
},
|
||||
{
|
||||
"title": "Pingvin Share",
|
||||
"hex": "485099"
|
||||
"title": "Pingvin Share"
|
||||
},
|
||||
{
|
||||
"title": "Plutus",
|
||||
@@ -466,12 +483,10 @@
|
||||
"title": "Poloniex"
|
||||
},
|
||||
{
|
||||
"title": "Porkbun",
|
||||
"hex": "F27777"
|
||||
"title": "Porkbun"
|
||||
},
|
||||
{
|
||||
"title": "PostNL",
|
||||
"color": "EF8300"
|
||||
"title": "PostNL"
|
||||
},
|
||||
{
|
||||
"title": "Privacy Guides",
|
||||
@@ -495,7 +510,6 @@
|
||||
"title": "Registro br",
|
||||
"slug": "registro_br",
|
||||
"altNames": [
|
||||
"Registro br",
|
||||
"registrobr",
|
||||
"Registro.br"
|
||||
]
|
||||
@@ -507,13 +521,15 @@
|
||||
"title": "Revolt",
|
||||
"hex": "858585"
|
||||
},
|
||||
{
|
||||
"title": "RippleMatch"
|
||||
},
|
||||
{
|
||||
"title": "Rockstar Games",
|
||||
"slug": "rockstar_games"
|
||||
},
|
||||
{
|
||||
"title": "RuneMate",
|
||||
"hex": "2ECC71"
|
||||
"title": "RuneMate"
|
||||
},
|
||||
{
|
||||
"title": "Rust Language Forum",
|
||||
@@ -529,6 +545,9 @@
|
||||
{
|
||||
"title": "service-bw"
|
||||
},
|
||||
{
|
||||
"title": "Shakepay"
|
||||
},
|
||||
{
|
||||
"title": "SimpleLogin"
|
||||
},
|
||||
@@ -551,16 +570,14 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "SMTP2GO",
|
||||
"slug": "smtp2go"
|
||||
"title": "SMTP2GO"
|
||||
},
|
||||
{
|
||||
"title": "Snapchat"
|
||||
},
|
||||
{
|
||||
"title": "Standard Notes",
|
||||
"slug": "standardnotes",
|
||||
"hex": "2173E6"
|
||||
"slug": "standardnotes"
|
||||
},
|
||||
{
|
||||
"title": "Surfshark"
|
||||
@@ -570,9 +587,7 @@
|
||||
"slug": "synology_dsm"
|
||||
},
|
||||
{
|
||||
"title": "TCPShield",
|
||||
"slug": "tcpshield",
|
||||
"hex": "FFFFFF"
|
||||
"title": "TCPShield"
|
||||
},
|
||||
{
|
||||
"title": "Techlore",
|
||||
@@ -596,9 +611,7 @@
|
||||
"title": "TorGuard"
|
||||
},
|
||||
{
|
||||
"title": "Trading 212",
|
||||
"slug": "trading212",
|
||||
"hex": "4BA4DE"
|
||||
"title": "Trading 212"
|
||||
},
|
||||
{
|
||||
"title": "TradingView"
|
||||
@@ -635,13 +648,16 @@
|
||||
"hex": "858585"
|
||||
},
|
||||
{
|
||||
"title": "Uphold",
|
||||
"slug": "uphold",
|
||||
"hex": "6FE68A"
|
||||
"title": "Uphold"
|
||||
},
|
||||
{
|
||||
"titile": "Vikunja",
|
||||
"slug": "vikunja"
|
||||
"title": "Upstox"
|
||||
},
|
||||
{
|
||||
"title": "Vikunja"
|
||||
},
|
||||
{
|
||||
"title": "Wealthfront"
|
||||
},
|
||||
{
|
||||
"title": "Wealthsimple"
|
||||
@@ -656,74 +672,30 @@
|
||||
{
|
||||
"title": "Wise"
|
||||
},
|
||||
{
|
||||
"title": "WYZE",
|
||||
"slug": "wyze"
|
||||
},
|
||||
{
|
||||
"title": "WorkOS",
|
||||
"slug": "workos",
|
||||
"altNames": [
|
||||
"Work OS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "X",
|
||||
"altNames": [
|
||||
"twitter"
|
||||
],
|
||||
"slug": "x"
|
||||
"title": "WYZE"
|
||||
},
|
||||
{
|
||||
"title": "yahoo"
|
||||
},
|
||||
{
|
||||
"title": "Yandex",
|
||||
"altNames": [
|
||||
"Ya",
|
||||
"Яндекс"
|
||||
],
|
||||
"slug": "Yandex"
|
||||
},
|
||||
{
|
||||
"title": "yahoo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "YNAB",
|
||||
"altNames": [
|
||||
"You Need A Budget"
|
||||
],
|
||||
"slug": "ynab",
|
||||
"hex": "3B5EDA"
|
||||
},
|
||||
{
|
||||
"title": "Shakepay",
|
||||
"slug": "shakepay"
|
||||
},
|
||||
{
|
||||
"title": "Newton",
|
||||
"altNames": ["Newton Crypto"],
|
||||
"slug": "newton"
|
||||
},
|
||||
{
|
||||
"title": "T-Mobile ID",
|
||||
"altNames": [
|
||||
"T-Mobile"
|
||||
],
|
||||
"slug": "t-mobile"
|
||||
},
|
||||
{
|
||||
"title": "Wealthfront",
|
||||
"slug": "wealthfront"
|
||||
},
|
||||
{
|
||||
"title": "BinanceUS",
|
||||
"altNames": [
|
||||
"Binance US"
|
||||
],
|
||||
"slug": "binance_us"
|
||||
},
|
||||
{
|
||||
"title": "Bethesda Softworks",
|
||||
"altNames": ["Bethesda"],
|
||||
"slug": "bethesda"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
6
auth/assets/custom-icons/icons/amazon.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M442.375 441.562C390.672 479.687 315.75 500 251.25 500C160.625 500 79.344 466.562 17.7346 410.89C13.0471 406.515 17.2346 400.547 23.0471 403.953C89.5315 442.656 171.875 465.937 256.656 465.937C317.884 465.655 378.451 453.272 434.875 429.5C443.625 425.781 450.969 435.218 442.375 441.562ZM463.875 416.968C457.313 408.531 420.188 412.984 403.563 414.937C398.485 415.562 397.719 411.14 402.281 407.968C431.969 387.187 480.313 393.172 485.969 400.156C491.625 407.14 484.5 455.781 456.75 478.968C452.485 482.531 448.422 480.64 450.5 475.906C456.75 460.343 470.719 425.437 464.094 416.968" fill="#FF9900"/>
|
||||
<g style="mix-blend-mode:difference">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M287.969 216.625C287.969 243.063 288.641 265.109 275.281 288.578C264.344 307.641 247.156 319.406 228.328 319.406C202.281 319.406 187.016 299.563 187.016 270.266C187.016 212.453 238.828 201.938 287.984 201.938L287.969 216.625ZM356.422 382C351.938 386.016 345.453 386.297 340.391 383.625C317.891 364.922 313.766 356.234 301.453 338.391C264.234 376.359 237.797 387.719 189.609 387.719C132.453 387.719 88.0781 352.5 88.0781 281.984C88.0781 226.922 117.844 189.422 160.422 171.094C197.25 154.875 248.703 152.031 288 147.656V139.062C288 122.938 289.25 103.844 279.719 89.9219C271.516 77.4219 255.656 72.2656 241.641 72.2656C215.781 72.2656 192.781 85.5469 187.156 113.016C186.016 119.266 181.531 125.141 175.328 125.422L109.375 118.047C103.844 116.797 97.6563 112.328 99.2656 103.984C114.5 24.0625 186.641 0 251.156 0C284.172 0 327.313 8.78125 353.344 33.7812C386.359 64.6094 383.219 105.734 383.219 150.5V256.25C383.219 288.031 396.391 301.953 408.797 319.141C413.094 325.391 414.047 332.578 408.516 337.172C391.003 351.98 373.669 366.997 356.516 382.219L356.422 382.031" fill="white"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
10
auth/assets/custom-icons/icons/battlenet.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_181_130)">
|
||||
<path d="M394.583 172.833C331.25 143.583 240.292 125 154.708 131.917C159 103.583 169.583 83.8334 186.958 79.6667C210.875 73.9376 236.958 89.6667 261.833 118.292C278.125 120.417 297.458 124.125 310.896 127.229C265.562 41.9375 204.75 -5.87495 158.479 11.7709C123.312 25.1876 105.292 73.6459 107.479 138.729C61.6457 148.479 25.9166 165.813 3.04156 190.708C1.8749 192.063 -0.729272 195.438 0.187395 197.063C0.895728 198.271 3.22906 196.896 4.22906 196.229C30.7707 177.688 64.7291 167.625 108.958 161.313C115.271 230.75 144.646 318.813 193.437 389.479C166.771 399.938 144.354 400.646 132.062 387.667C115.146 369.833 115.729 339.375 128.104 303.5C121.802 288.106 116.192 272.437 111.292 256.542C60.0624 338.5 49.0832 415.083 87.4791 446.333C116.687 470.083 167.625 461.438 222.937 427.042C254.292 461.875 287.167 484.125 320.167 491.5C321.917 491.813 326.146 492.396 327.083 490.792C327.792 489.542 325.417 488.208 324.354 487.688C295.021 474 269.354 449.604 241.771 414.458C298.75 374.271 360.333 304.813 397.125 227.208C419.542 245.125 431.292 264.146 426.25 281.271C419.25 304.833 392.604 319.604 355.354 326.792C345.157 339.931 334.397 352.624 323.104 364.833C419.646 368.167 491.437 339.417 499.312 290.563C505.271 253.354 472.333 213.563 414.875 182.854C429.375 138.292 432.208 98.6876 422.083 66.4376C421.479 64.7709 419.875 60.8126 418 60.8126C416.583 60.8126 416.604 63.5209 416.687 64.7084C419.5 96.9376 411.208 131.375 394.562 172.833H394.583ZM216.812 378.438C175.979 312.917 152.437 235.75 152.604 157.729C229.729 155.146 308.312 173.313 375.812 212.458C339.5 280.563 284.458 339.542 216.792 378.417L216.812 378.438Z" fill="#148EFF"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_181_130">
|
||||
<rect width="500" height="500" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
6
auth/assets/custom-icons/icons/capacities.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="100%" height="100%" viewBox="0 0 78 78" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g style="mix-blend-mode:difference">
|
||||
<circle cx="38.8209" cy="39" r="13.45" transform="rotate(-15 38.8209 39)" fill="white"></circle>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M54.7914 66.0811C54.6942 66.3374 54.5105 66.5518 54.271 66.6852C52.0346 67.9311 49.6099 68.9243 47.0245 69.617C30.1152 74.1478 12.7346 64.1131 8.20379 47.2038C3.67296 30.2946 13.7077 12.9139 30.6169 8.38311C33.2023 7.69037 35.7987 7.33813 38.3584 7.2989C38.6325 7.29469 38.8988 7.38849 39.1111 7.56192C41.8794 9.82347 44.4239 12.3787 46.6916 15.197C47.4731 16.1681 46.2983 17.5912 45.101 17.2444C41.2693 16.1343 37.0954 16.023 32.9609 17.1308C20.8828 20.3671 13.7152 32.7819 16.9515 44.8599C20.1878 56.938 32.6025 64.1056 44.6806 60.8693C48.8151 59.7615 52.3742 57.5781 55.1375 54.7009C56.001 53.8018 57.7299 54.4469 57.5387 55.6787C56.9839 59.2532 56.058 62.7384 54.7914 66.0811ZM65.4625 56.1737C64.7914 57.2153 63.3044 56.5354 63.4669 55.307C64.4343 47.9938 64.0074 40.3692 61.9779 32.7952C59.9484 25.2211 56.5058 18.4044 52.0114 12.5547C51.2565 11.5722 52.2043 10.2398 53.3063 10.8064C60.9824 14.7532 67.0278 21.8023 69.4377 30.7963C71.8476 39.7902 70.1368 48.9176 65.4625 56.1737Z" fill="white"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -1,3 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 430.964 500">
|
||||
<path d="m156.633 323.503-6.557 16.51h12.996l-6.439-16.51Zm38.498-171.881v-48.197c0-7.683-3.53-11.231-10.894-11.231h-11.986v70.676h11.986c7.364 0 10.894-3.564 10.894-11.23v-.018ZM391.791 0H39.138C10.524 0 0 10.541 0 39.138V384.21l.42 9.027c.64 6.255.791 12.307 6.591 19.165 2.11 1.765 4.28 3.458 6.505 5.078l8.961 4.169 173.646 72.743c9.027 4.119 12.777 5.75 19.333 5.598h.05c6.557.135 10.306-1.479 19.335-5.598l173.645-72.743 8.961-4.169 6.505-5.077c5.8-6.893 5.934-12.945 6.591-19.165.293-3.001.433-6.014.42-9.029V39.155c0-28.614-10.558-39.138-39.138-39.138h-.033V0h-.001ZM237.447 66.441h29.168v191.715h-29.168V66.44v.001Zm1.966 238.403h16.98v57.999h-16.004v-33.32l-14.829 22.695h-.337l-14.743-22.527v33.151h-15.752v-57.999h16.979l13.837 22.477 13.835-22.477h.034v.001ZM143.083 66.44h45.778c23.704 0 35.438 11.768 35.438 35.607v50.938c0 23.822-11.717 35.607-35.438 35.607h-16.61v69.582h-29.168V66.439v.001Zm-79.501 0h64.875v26.561H92.75v54.216h34.346v26.562H92.75v57.798h36.262v26.562h-65.43V66.44Zm55.763 288.635c-6.136 5.044-14.676 8.944-25.183 8.944-18.073 0-31.572-12.439-31.572-30.008v-.168c0-16.896 13.247-30.177 31.235-30.177 10.205 0 17.401 3.143 23.536 8.457l-9.447 11.347c-4.153-3.48-8.289-5.464-14.005-5.464-8.372 0-14.828 7.027-14.828 15.921v.168c-.466 8.938 6.806 16.366 15.752 16.088 3.901 0 6.893-.84 9.281-2.403v-7.028H92.683v-11.769h26.68v26.11l-.018-.018Zm29.672-50.635h15.5l24.679 58.419h-17.231l-4.236-10.373h-22.393l-4.154 10.373h-16.894l24.678-58.419h.052-.001Zm65.128 155.186-81.736-28.108h166.955l-85.218 28.109-.001-.001Zm99.978-96.75h-47.072v-57.999h46.652v13.667h-30.732v8.793h27.857v12.693h-27.857v9.195h31.169v13.668-.034l-.017.017Zm-32.06-138.677V100.398c0-23.822 11.717-35.607 35.438-35.607h14.172c23.704 0 35.169 11.517 35.169 35.338V139.3H338.23v-37.523c0-7.682-3.564-11.23-10.894-11.23h-4.91c-7.615 0-11.178 3.564-11.178 11.23V222.82c0 7.682 3.563 11.23 11.178 11.23h5.465c7.363 0 10.893-3.565 10.893-11.23v-43.256h28.614v44.634c0 23.822-11.718 35.624-35.439 35.624h-14.458c-23.704 0-35.438-11.768-35.438-35.623Zm86.831 120.772c0 11.853-9.364 18.88-23.452 18.88-10.289 0-20.056-3.228-27.185-9.616l8.944-10.709a29.76 29.76 0 0 0 18.795 6.944c4.321 0 6.641-1.48 6.641-3.985v-.168c0-2.404-1.9-3.732-9.784-5.548-12.357-2.824-21.889-6.304-21.889-18.241v-.168c0-10.793 8.541-18.576 22.477-18.576 9.868 0 17.568 2.656 23.872 7.699l-8.036 11.349c-5.295-3.733-11.095-5.717-16.256-5.717-3.901 0-5.8 1.648-5.8 3.733v.167c0 2.656 1.983 3.817 10.036 5.633 13.331 2.908 21.637 7.195 21.637 18.071v.252Z"/>
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g style="mix-blend-mode:difference">
|
||||
<path d="M191.633 323.503L185.076 340.013H198.072L191.633 323.503ZM230.131 151.622V103.425C230.131 95.742 226.601 92.194 219.237 92.194H207.251V162.87H219.237C226.601 162.87 230.131 159.306 230.131 151.64V151.622ZM426.791 0H74.138C45.524 0 35 10.541 35 39.138V384.21L35.42 393.237C36.06 399.492 36.211 405.544 42.011 412.402C44.121 414.167 46.291 415.86 48.516 417.48L57.477 421.649L231.123 494.392C240.15 498.511 243.9 500.142 250.456 499.99H250.506C257.063 500.125 260.812 498.511 269.841 494.392L443.486 421.649L452.447 417.48L458.952 412.403C464.752 405.51 464.886 399.458 465.543 393.238C465.836 390.237 465.976 387.224 465.963 384.209V39.155C465.963 10.541 455.405 0.017 426.825 0.017H426.792V0H426.791ZM272.447 66.441H301.615V258.156H272.447V66.441ZM274.413 304.844H291.393V362.843H275.389V329.523L260.56 352.218H260.223L245.48 329.691V362.842H229.728V304.843H246.707L260.544 327.32L274.379 304.843H274.413V304.844ZM178.083 66.44H223.861C247.565 66.44 259.299 78.208 259.299 102.047V152.985C259.299 176.807 247.582 188.592 223.861 188.592H207.251V258.174H178.083V66.44ZM98.582 66.44H163.457V93.001H127.75V147.217H162.096V173.779H127.75V231.577H164.012V258.139H98.582V66.44ZM154.345 355.075C148.209 360.119 139.669 364.019 129.162 364.019C111.089 364.019 97.59 351.58 97.59 334.011V333.843C97.59 316.947 110.837 303.666 128.825 303.666C139.03 303.666 146.226 306.809 152.361 312.123L142.914 323.47C138.761 319.99 134.625 318.006 128.909 318.006C120.537 318.006 114.081 325.033 114.081 333.927V334.095C113.615 343.033 120.887 350.461 129.833 350.183C133.734 350.183 136.726 349.343 139.114 347.78V340.752H127.683V328.983H154.363V355.093L154.345 355.075ZM184.017 304.44H199.517L224.196 362.859H206.965L202.729 352.486H180.336L176.182 362.859H159.288L183.966 304.44H184.018H184.017ZM249.145 459.626L167.409 431.518H334.364L249.146 459.627L249.145 459.626ZM349.123 362.876H302.051V304.877H348.703V318.544H317.971V327.337H345.828V340.03H317.971V349.225H349.14V362.893V362.859L349.123 362.876ZM317.063 224.199V100.398C317.063 76.576 328.78 64.791 352.501 64.791H366.673C390.377 64.791 401.842 76.308 401.842 100.129V139.3H373.23V101.777C373.23 94.095 369.666 90.547 362.336 90.547H357.426C349.811 90.547 346.248 94.111 346.248 101.777V222.82C346.248 230.502 349.811 234.05 357.426 234.05H362.891C370.254 234.05 373.784 230.485 373.784 222.82V179.564H402.398V224.198C402.398 248.02 390.68 259.822 366.959 259.822H352.501C328.797 259.822 317.063 248.054 317.063 224.199ZM403.894 344.971C403.894 356.824 394.53 363.851 380.442 363.851C370.153 363.851 360.386 360.623 353.257 354.235L362.201 343.526C367.475 347.944 374.117 350.397 380.996 350.47C385.317 350.47 387.637 348.99 387.637 346.485V346.317C387.637 343.913 385.737 342.585 377.853 340.769C365.496 337.945 355.964 334.465 355.964 322.528V322.36C355.964 311.567 364.505 303.784 378.441 303.784C388.309 303.784 396.009 306.44 402.313 311.483L394.277 322.832C388.982 319.099 383.182 317.115 378.021 317.115C374.12 317.115 372.221 318.763 372.221 320.848V321.015C372.221 323.671 374.204 324.832 382.257 326.648C395.588 329.556 403.894 333.843 403.894 344.719V344.971Z" fill="white"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.2 KiB |
5
auth/assets/custom-icons/icons/gov_uk.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 30">
|
||||
<g style="mix-blend-mode:difference">
|
||||
<path d="M22.6 10.4c-1 .4-2-.1-2.4-1s.1-2 1-2.4 2 .1 2.4 1-.1 2-1 2.4m-5.9 6.7c-.9.4-2-.1-2.4-1s.1-2 1-2.4 2 .1 2.4 1-.1 2-1 2.4m10.8-3.7c-1 .4-2-.1-2.4-1s.1-2 1-2.4 2 .1 2.4 1 0 2-1 2.4m3.3 4.8c-1 .4-2-.1-2.4-1s.1-2 1-2.4 2 .1 2.4 1-.1 2-1 2.4M17 4.7l2.3 1.2V2.5l-2.3.7-.2-.2.9-3h-3.4l.9 3-.2.2c-.1.1-2.3-.7-2.3-.7v3.4L15 4.7c.1.1.1.2.2.2l-1.3 4c-.1.2-.1.4-.1.6 0 1.1.8 2 1.9 2.2h.7c1-.2 1.9-1.1 1.9-2.1 0-.2 0-.4-.1-.6l-1.3-4c-.1-.2 0-.2.1-.3m-7.6 5.7c.9.4 2-.1 2.4-1s-.1-2-1-2.4-2 .1-2.4 1 0 2 1 2.4m-5 3c.9.4 2-.1 2.4-1s-.1-2-1-2.4-2 .1-2.4 1 .1 2 1 2.4m-3.2 4.8c.9.4 2-.1 2.4-1s-.1-2-1-2.4-2 .1-2.4 1 0 2 1 2.4m14.8 11c4.4 0 8.6.3 12.3.8 1.1-4.5 2.4-7 3.7-8.8l-2.5-.9c.2 1.3.3 1.9 0 2.7-.4-.4-.8-1.1-1.1-2.3l-1.2 4c.7-.5 1.3-.8 2-.9-1.1 2.5-2.6 3.1-3.5 3-1.1-.2-1.7-1.2-1.5-2.1.3-1.2 1.5-1.5 2.1-.1 1.1-2.3-.8-3-2-2.3 1.9-1.9 2.1-3.5.6-5.6-2.1 1.6-2.1 3.2-1.2 5.5-1.2-1.4-3.2-.6-2.5 1.6.9-1.4 2.1-.5 1.9.8-.2 1.1-1.7 2.1-3.5 1.9-2.7-.2-2.9-2.1-2.9-3.6.7-.1 1.9.5 2.9 1.9l.4-4.3c-1.1 1.1-2.1 1.4-3.2 1.4.4-1.2 2.1-3 2.1-3h-5.4s1.7 1.9 2.1 3c-1.1 0-2.1-.2-3.2-1.4l.4 4.3c1-1.4 2.2-2 2.9-1.9-.1 1.5-.2 3.4-2.9 3.6-1.9.2-3.4-.8-3.5-1.9-.2-1.3 1-2.2 1.9-.8.7-2.3-1.2-3-2.5-1.6.9-2.2.9-3.9-1.2-5.5-1.5 2-1.3 3.7.6 5.6-1.2-.7-3.1 0-2 2.3.6-1.4 1.8-1.1 2.1.1.2.9-.3 1.9-1.5 2.1-.9.2-2.4-.5-3.5-3 .6 0 1.2.3 2 .9l-1.2-4c-.3 1.1-.7 1.9-1.1 2.3-.3-.8-.2-1.4 0-2.7l-2.9.9C1.3 23 2.6 25.5 3.7 30c3.7-.5 7.9-.8 12.3-.8" fill="white"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -1,18 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
|
||||
<defs>
|
||||
<linearGradient id="a" x1=".425" x2="0" y1=".821" y2="0">
|
||||
<stop stop-color="#F4AAFF" stop-opacity="0"/>
|
||||
<stop offset="1" stop-color="#F000FB" stop-opacity=".4"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="b" x1=".365" x2="0" y1=".566" y2="-.048">
|
||||
<stop stop-color="#F7D2FE" stop-opacity="0"/>
|
||||
<stop offset="1" stop-color="#F7D2FE"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g stroke="null">
|
||||
<rect width="500" height="500" fill="#7132F5" rx="64"/>
|
||||
<rect width="500" height="500" fill="url(#a)" fill-opacity=".64" rx="64"/>
|
||||
<rect width="500" height="500" fill="url(#b)" fill-opacity=".4" rx="64"/>
|
||||
<path fill="#fff" fill-rule="evenodd" d="M110.63 269.996v60.347c0 11.113 8.888 20.106 19.818 20.106 10.94 0 19.87-8.993 19.87-20.106v-60.347c0-11.129 8.842-20.137 19.828-20.137 10.948 0 19.829 9.008 19.829 20.137v60.347c0 11.113 8.887 20.106 19.827 20.106 10.98 0 19.864-8.993 19.864-20.106v-60.347c0-11.129 8.88-20.137 19.823-20.137 10.991 0 19.878 9.008 19.878 20.137v60.347c0 11.113 8.885 20.106 19.813 20.106 10.941 0 19.829-8.993 19.829-20.106v-60.347c0-11.129 8.883-20.137 19.87-20.137 10.945 0 19.828 9.008 19.828 20.137v60.347c0 11.113 8.888 20.106 19.86 20.106 10.944 0 19.828-8.993 19.828-20.106v-60.347c0-77.78-62.194-140.848-138.906-140.848-76.706 0-138.858 63.067-138.858 140.848z" clip-rule="evenodd"/>
|
||||
</g>
|
||||
</svg>
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M233.918 53.5499C277.36 50.6259 321.637 59.3977 360.485 79.0302C418.129 107.435 464.077 158.395 485.38 218.546C494.987 245.279 500 273.266 500 301.67V406.516C500 410.693 500 415.287 499.165 419.465C496.658 429.907 489.14 439.515 479.114 444.11C472.013 447.451 464.077 447.869 456.976 446.616C441.103 443.692 428.571 428.654 428.571 412.364C428.571 379.782 428.571 347.201 428.571 314.619C428.989 305.43 428.989 295.405 423.977 287.468C416.04 272.43 395.99 265.329 380.535 271.595C367.168 276.19 357.561 289.974 357.143 304.176C357.143 337.176 357.143 370.175 357.143 403.174C357.143 409.44 357.561 415.705 355.472 421.553C352.13 433.249 342.523 442.439 330.827 445.78C315.372 449.958 297.828 443.274 290.309 429.072C284.879 420.718 285.297 410.275 285.714 400.668C285.714 367.668 285.714 335.087 285.714 302.088C285.297 285.379 271.512 270.342 255.221 268.253C244.361 266.582 233.083 270.342 225.146 277.861C218.045 284.544 214.286 294.151 214.286 303.759V399.414C214.286 407.351 215.121 415.705 212.197 423.224C207.602 437.009 193.818 447.033 179.198 446.616C164.16 447.451 149.541 437.009 144.946 423.224C142.439 416.123 142.857 409.022 142.857 401.503C142.857 368.504 142.857 335.505 142.857 302.506C142.857 286.215 129.908 271.177 114.035 268.253C99.4152 265.329 83.5422 272.43 76.0234 285.797C73.0994 291.227 71.4286 297.493 71.4286 303.759V411.11C71.4286 421.553 66.8337 431.996 58.8972 438.679C46.7836 449.122 27.1512 449.957 14.6199 440.35C5.43024 434.084 0 423.224 0 411.946V303.341C0 262.405 10.4428 221.47 30.0752 185.129C45.9482 155.471 68.0869 129.155 94.4027 108.27C133.25 75.6885 182.957 56.4739 233.918 53.5499Z" fill="#5741D9"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2500 2500" xmlns:v="https://vecta.io/nano"><path d="M830.3 1250.3l740.5 740.6 467.4-467.4c83.6-75.2 211.4-71.9 290.9 7.6s82.9 207.4 7.6 290.9l-616.8 616.9c-82.9 81.5-215.7 81.5-298.6 0l-889.8-890.1v529c0 116.8-94.6 211.4-211.4 211.4s-211.4-94.6-211.4-211.4V422c0-116.7 94.6-211.4 211.4-211.4S531.5 305.3 531.5 422v529l889.7-889.9c82.8-81.5 215.8-81.5 298.6 0L2337 677.9c75.2 83.6 71.9 211.4-7.6 290.9s-207.4 82.9-290.9 7.6L1571.1 509l-740.8 741.3h0zm740.8-211.7h0c-85.6 0-162.8 51.5-195.6 130.6s-14.7 170.1 45.8 230.7 151.6 78.7 230.7 46c79.1-32.8 130.7-109.9 130.7-195.6a211.87 211.87 0 0 0-61.9-149.7c-39.6-39.7-93.5-62-149.6-62h-.1 0z" fill-rule="evenodd" fill="#23af91"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2500 2500" xmlns:v="https://vecta.io/nano"><path d="M830.3 1250.3l740.5 740.6 467.4-467.4c83.6-75.2 211.4-71.9 290.9 7.6s82.9 207.4 7.6 290.9l-616.8 616.9c-82.9 81.5-215.7 81.5-298.6 0l-889.8-890.1v529c0 116.8-94.6 211.4-211.4 211.4s-211.4-94.6-211.4-211.4V422c0-116.7 94.6-211.4 211.4-211.4S531.5 305.3 531.5 422v529l889.7-889.9c82.8-81.5 215.8-81.5 298.6 0L2337 677.9c75.2 83.6 71.9 211.4-7.6 290.9s-207.4 82.9-290.9 7.6L1571.1 509l-740.8 741.3h0zm740.8-211.7h0c-85.6 0-162.8 51.5-195.6 130.6s-14.7 170.1 45.8 230.7 151.6 78.7 230.7 46c79.1-32.8 130.7-109.9 130.7-195.6a211.87 211.87 0 0 0-61.9-149.7c-39.6-39.7-93.5-62-149.6-62h-.1 0z" fill-rule="evenodd" fill="#01BC8D"/></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 735 B After Width: | Height: | Size: 735 B |
@@ -1,30 +1,34 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
|
||||
<defs>
|
||||
<linearGradient id="a" x1="0" x2="1" y1="0" y2="0" gradientTransform="rotate(45.043 -14.606 34.73) scale(128.4643)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#2e79ef"/>
|
||||
<stop offset="1" stop-color="#389d93"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="b" x1="0" x2="1" y1="0" y2="0" gradientTransform="rotate(-90 191.946 -57.554) scale(132.907)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fbb94b"/>
|
||||
<stop offset="1" stop-color="#fc7e27"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="c" x1="0" x2="1" y1="0" y2="0" gradientTransform="rotate(-62.181 250.835 -202.634) scale(119.902)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fdaf60"/>
|
||||
<stop offset="1" stop-color="#ab82d5"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="d" x1="0" x2="1" y1="0" y2="0" gradientTransform="rotate(45.043 168.839 476.151) scale(130.8827)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fc9aa2"/>
|
||||
<stop offset="1" stop-color="#7269fe"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="e" x1="0" x2="1" y1="0" y2="0" gradientTransform="translate(141.309 66.467) scale(66.239)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#87b391"/>
|
||||
<stop offset="1" stop-color="#dfb962"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path stroke="#000" d="M0 0h500v500H0z"/>
|
||||
<path fill="url(#a)" d="M66.25.299c36.803.028 66.576 29.747 66.549 66.247-.027 36.606-29.845 66.183-66.549 66.155-36.796.071-66.577-29.648-66.549-66.254C-.272 29.947 29.553.272 66.25.299Z" transform="matrix(-.00052 .70126 .70126 .00052 74.86 203.507)"/>
|
||||
<path fill="url(#b)" d="M216.401 0h66.197v133.099h-66.197z" transform="matrix(.70126 0 0 -.70126 75.035 296.669)"/>
|
||||
<path fill="url(#c)" d="M291.5 66.599c0-36.704 29.598-66.5 66.197-66.5v133c-36.5 0-66.197-29.802-66.197-66.5Z" transform="matrix(.70126 0 0 -.70126 75.035 296.738)"/>
|
||||
<path fill="url(#d)" d="M432.75.398c36.803-.071 66.577 29.648 66.549 66.254-.027 36.598-29.845 66.174-66.549 66.147-36.796-.027-66.576-29.747-66.549-66.246C366.228 29.947 396.053.371 432.75.398Z" transform="matrix(-.00052 .70126 .70126 .00052 332.064 -53.506)"/>
|
||||
<path fill="url(#e)" d="M141.303 0h.222c36.325.12 65.856 29.755 65.975 66.277v.446C207.381 103.319 177.827 133 141.303 133V0Z" transform="matrix(.70126 0 0 -.70126 75.035 296.599)"/>
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_191_1018)">
|
||||
<path d="M0.0492147 249.67C0.0499258 286.539 29.8004 316.388 66.3661 316.388C103.038 316.388 132.691 286.538 132.69 249.768C132.788 212.906 103.038 183.049 66.3658 183.05C29.8001 183.05 0.0494268 212.907 0.0492147 249.67Z" fill="url(#paint0_linear_191_1018)"/>
|
||||
<path d="M216.841 316.39H283.157V183.051H216.841V316.39Z" fill="url(#paint1_linear_191_1018)"/>
|
||||
<path d="M292.074 249.769C292.074 286.539 321.726 316.389 358.39 316.389V183.149C321.825 183.149 292.074 213.005 292.074 249.769Z" fill="url(#paint2_linear_191_1018)"/>
|
||||
<path d="M367.311 249.669C367.213 286.538 396.963 316.388 433.635 316.387C470.299 316.387 499.95 286.537 499.951 249.767C499.951 212.905 470.199 183.049 433.635 183.049C396.963 183.049 367.311 212.906 367.311 249.669Z" fill="url(#paint3_linear_191_1018)"/>
|
||||
<path d="M141.606 316.29H141.829C178.219 316.17 207.804 286.481 207.923 249.894V249.447C207.804 212.785 178.196 183.05 141.606 183.05V316.29Z" fill="url(#paint4_linear_191_1018)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_191_1018" x1="20.3472" y1="203.643" x2="111.35" y2="294.643" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#2E79EF"/>
|
||||
<stop offset="1" stop-color="#389D93"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_191_1018" x1="249.999" y1="181.755" x2="249.999" y2="314.902" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FBB94B"/>
|
||||
<stop offset="1" stop-color="#FC7E27"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_191_1018" x1="313.603" y1="202.507" x2="369.66" y2="308.742" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FDAF60"/>
|
||||
<stop offset="1" stop-color="#AB82D5"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_linear_191_1018" x1="387.221" y1="203.334" x2="479.936" y2="296.048" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FC9AA2"/>
|
||||
<stop offset="1" stop-color="#7269FE"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint4_linear_191_1018" x1="141.612" y1="249.703" x2="207.971" y2="249.703" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#87B391"/>
|
||||
<stop offset="1" stop-color="#DFB962"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_191_1018">
|
||||
<rect width="500" height="500" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -1,5 +1,12 @@
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M446.258 230.173C434.83 295.328 381.676 344.578 311.926 344.578H267.645C258.614 344.578 249.514 352.94 248.072 362.188L228.68 485.284C227.555 492.294 224.272 494.623 217.172 494.623H145.945C138.743 494.623 137.039 492.214 138.118 485.114L146.298 399.986L60.8024 395.566C53.6116 395.566 51.0102 391.647 52.0325 384.467L110.366 14.5526C111.491 7.54283 115.853 4.53217 122.93 4.53217H270.871C342.087 4.53217 387.14 52.4756 392.65 114.643C435.023 143.273 454.834 181.366 446.269 230.162L446.258 230.173Z" fill="#001C64"/>
|
||||
<path d="M167.972 262.157L146.309 400L132.609 486.48C132.354 488.148 132.462 489.85 132.924 491.472C133.386 493.094 134.192 494.598 135.287 495.881C136.382 497.163 137.741 498.195 139.27 498.906C140.8 499.617 142.464 499.99 144.151 500H219.376C222.81 499.996 226.13 498.767 228.739 496.535C231.348 494.303 233.075 491.213 233.61 487.821L253.411 362.168C253.949 358.778 255.677 355.691 258.286 353.461C260.895 351.231 264.213 350.004 267.645 350.001H311.926C345.668 349.957 378.285 337.859 403.896 315.889C429.507 293.919 446.428 263.521 451.608 230.176C459.276 181.244 434.659 136.698 392.525 114.692C392.43 119.905 391.974 125.106 391.162 130.256C385.962 163.584 369.035 193.96 343.428 215.913C317.822 237.867 285.219 249.955 251.491 250.001H182.195C178.766 250.002 175.449 251.227 172.842 253.456C170.235 255.684 168.508 258.77 167.972 262.157Z" fill="#0070E0"/>
|
||||
<path d="M146.297 399.998H58.7005C57.0105 399.99 55.3422 399.617 53.8091 398.906C52.276 398.195 50.9144 397.161 49.8168 395.876C48.7193 394.591 47.9117 393.084 47.4491 391.458C46.9864 389.833 46.8797 388.126 47.1361 386.456L106.163 12.179C106.693 8.78702 108.418 5.6961 111.025 3.46315C113.633 1.23021 116.952 0.00205828 120.385 0H270.791C342.007 0 393.786 51.8289 392.57 114.621C373.615 104.841 352.565 99.8231 331.238 99.9995H205.846C202.412 100 199.091 101.226 196.48 103.456C193.869 105.687 192.139 108.775 191.601 112.167L167.972 262.155L146.297 399.998Z" fill="#003087"/>
|
||||
<g clip-path="url(#clip0_203_147)">
|
||||
<path d="M395.978 115C395.978 176.933 338.822 250 252.345 250H169.045L164.956 275.8L145.522 400H42.0002L104.278 0H272C328.478 0 372.911 31.4778 389.278 75.2222C393.998 87.9408 396.271 101.437 395.978 115Z" fill="#002991"/>
|
||||
<path d="M455.645 230C450.119 263.571 432.827 294.081 406.862 316.067C380.898 338.054 347.956 350.082 313.933 350H256.089L232.011 500H129.045L145.522 400L164.967 275.8L169.045 250H252.345C338.711 250 395.978 176.933 395.978 115C438.478 136.933 463.256 181.256 455.645 230Z" fill="#60CDFF"/>
|
||||
<path d="M395.978 115C378.156 105.678 356.545 100 333.022 100H192.578L169.045 250H252.345C338.711 250 395.978 176.933 395.978 115Z" fill="#008CFF"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_203_147">
|
||||
<rect width="500" height="500" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 914 B |
@@ -1,4 +1,13 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 484.002 500">
|
||||
<path d="M250 0c4.7 0 9.37.13 14.002.386V116.96a133.128 133.128 0 0 0-16.003-.958c-72.17 0-130.815 57.92-131.983 129.815l-.015 2.183v213.09C46.268 416.73.001 338.768.001 250 0 111.926 111.93 0 250 0Zm-2 159.997c4.918 0 9.743.406 14.44 1.183l1.562.27V248l.005 1.474c.313 28.493 9.651 54.814 25.294 76.251-12.314 6.556-26.373 10.276-41.302 10.276-48.597 0-87.997-39.4-87.997-88.002s39.4-88.002 87.997-88.002Z"/>
|
||||
<path fill="#00E6A5" d="M159.997 346.387c23.355 20.901 54.193 33.61 88.002 33.61 27.425 0 52.896-8.363 74.001-22.678 21.104 14.315 46.575 22.678 74 22.678 31.386 0 60.212-10.953 82.87-29.244C440.121 438.641 352.223 500 250 500c-31.724 0-62.073-5.909-90.003-16.69V346.386ZM396 159.997c48.603 0 88.002 39.4 88.002 88.002S444.603 336.001 396 336.001c-14.924 0-28.983-3.72-41.297-10.276 15.91-21.802 25.3-48.67 25.3-77.726 0-29.056-9.39-55.924-25.305-77.726 12.32-6.556 26.378-10.276 41.302-10.276Zm-74 40.358c8.858 13.731 14.001 30.088 14.001 47.644 0 17.556-5.143 33.913-14 47.644-8.86-13.73-14.003-30.088-14.003-47.644 0-17.07 4.862-33.006 13.272-46.497l.73-1.147ZM308.003 6.765c74.407 17.673 135.933 68.61 168.007 136.233C453.806 126.058 426.08 116 396.001 116c-27.425 0-52.896 8.363-74 22.678a131.582 131.582 0 0 0-12.189-7.343l-1.808-.943V6.764Z"/>
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_191_1037)">
|
||||
<g style="mix-blend-mode:difference">
|
||||
<path d="M257.999 0C262.699 0 267.369 0.13 272.001 0.386V116.96C266.691 116.319 261.347 116 255.998 116.002C183.828 116.002 125.183 173.922 124.015 245.817L124 248V461.09C54.267 416.73 8 338.768 8 250C7.999 111.926 119.929 0 257.999 0ZM255.999 159.997C260.917 159.997 265.742 160.403 270.439 161.18L272.001 161.45V248L272.006 249.474C272.319 277.967 281.657 304.288 297.3 325.725C284.986 332.281 270.927 336.001 255.998 336.001C207.401 336.001 168.001 296.601 168.001 247.999C168.001 199.397 207.401 159.997 255.998 159.997H255.999Z" fill="white"/>
|
||||
</g>
|
||||
<path d="M167.996 346.387C191.351 367.288 222.189 379.997 255.998 379.997C283.423 379.997 308.894 371.634 329.999 357.319C351.103 371.634 376.574 379.997 403.999 379.997C435.385 379.997 464.211 369.044 486.869 350.753C448.12 438.641 360.222 500 257.999 500C226.275 500 195.926 494.091 167.996 483.31V346.386V346.387ZM403.999 159.997C452.602 159.997 492.001 199.397 492.001 247.999C492.001 296.601 452.602 336.001 403.999 336.001C389.075 336.001 375.016 332.281 362.702 325.725C378.612 303.923 388.002 277.055 388.002 247.999C388.002 218.943 378.612 192.075 362.697 170.273C375.017 163.717 389.075 159.997 403.999 159.997ZM329.999 200.355C338.857 214.086 344 230.443 344 247.999C344 265.555 338.857 281.912 330 295.643C321.14 281.913 315.997 265.555 315.997 247.999C315.997 230.929 320.859 214.993 329.269 201.502L329.999 200.355ZM316.002 6.76516C390.409 24.4382 451.935 75.3752 484.009 142.998C461.805 126.058 434.079 116 404 116C376.575 116 351.104 124.363 330 138.678C326.073 136.012 322.004 133.561 317.811 131.335L316.003 130.392V6.76416L316.002 6.76516Z" fill="#00E6A5"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_191_1037">
|
||||
<rect width="500" height="500" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
@@ -1,4 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 433.451">
|
||||
<path d="M134.664 0c-10.257 0-19.193 1.837-27.87 5.518-8.421 3.682-15.784 8.678-22.36 15.255L250.4 202.779 416.102 20.773c-6.576-6.577-13.946-11.573-22.888-15.255C385.058 1.838 375.6 0 365.864 0c-10.257 0-19.986 2.108-28.664 6.054-8.942 3.94-16.312 9.729-23.146 16.563L250.4 93.105l-64.434-70.488c-6.576-6.834-13.945-12.624-23.152-16.563C154.664 2.108 144.922 0 134.664 0ZM250.4 230.4 84.434 412.678c6.576 6.312 13.939 11.566 22.36 15.254 8.677 3.681 17.627 5.519 27.355 5.519 10.787 0 19.987-2.366 28.665-6.055 9.207-4.203 17.091-9.729 23.667-16.562l63.92-70.488 63.911 70.488c6.576 6.833 13.946 12.359 22.888 16.562 8.678 3.689 18.142 6.055 28.665 6.055 9.735 0 19.193-1.838 27.349-5.519 8.942-3.688 16.312-8.942 22.888-15.254L250.4 230.4Z"/>
|
||||
<path fill="#e57000" d="M54.705 54.712c-10.522.264-20.78 2.359-29.98 6.305C15.255 64.963 7.098 70.488 0 77.329l126.787 139.396L0 355.865c7.098 7.104 15.254 12.616 24.725 16.826 9.2 4.21 19.458 6.055 29.98 6.577 11.308-.522 21.844-2.36 31.573-7.092 9.736-4.474 18.142-10.529 25.24-18.163l124.936-137.288L111.52 79.695c-7.627-7.37-15.777-13.417-25.512-18.15-9.729-4.467-19.994-6.569-31.302-6.833Zm390.333 0c-11.309.264-21.309 2.366-31.045 6.834-9.728 4.732-18.149 10.78-25.512 18.149l-124.406 137.03L388.48 354.013c7.363 7.634 15.784 13.689 25.512 18.163 9.736 4.732 19.736 6.57 31.045 7.092 11.308-.522 21.037-2.367 30.244-6.577 9.993-4.21 17.62-9.722 24.718-16.827L373.492 216.725 500 77.33c-7.098-6.841-14.725-12.366-24.718-16.312-9.207-3.946-18.936-6.04-30.244-6.305Z"/>
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g style="mix-blend-mode:difference">
|
||||
<path d="M134.664 33C124.407 33 115.471 34.837 106.794 38.518C98.3731 42.2 91.0101 47.196 84.4341 53.773L250.4 235.779L416.102 53.773C409.526 47.196 402.156 42.2 393.214 38.518C385.058 34.838 375.6 33 365.864 33C355.607 33 345.878 35.108 337.2 39.054C328.258 42.994 320.888 48.783 314.054 55.617L250.4 126.105L185.966 55.617C179.39 48.783 172.021 42.993 162.814 39.054C154.664 35.108 144.922 33 134.664 33ZM250.4 263.4L84.4341 445.678C91.0101 451.99 98.3731 457.244 106.794 460.932C115.471 464.613 124.421 466.451 134.149 466.451C144.936 466.451 154.136 464.085 162.814 460.396C172.021 456.193 179.905 450.667 186.481 443.834L250.401 373.346L314.312 443.834C320.888 450.667 328.258 456.193 337.2 460.396C345.878 464.085 355.342 466.451 365.865 466.451C375.6 466.451 385.058 464.613 393.214 460.932C402.156 457.244 409.526 451.99 416.102 445.678L250.4 263.4Z" fill="white"/>
|
||||
</g>
|
||||
<path d="M54.705 87.7119C44.183 87.9759 33.925 90.0709 24.725 94.0169C15.255 97.9629 7.098 103.488 0 110.329L126.787 249.725L0 388.865C7.098 395.969 15.254 401.481 24.725 405.691C33.925 409.901 44.183 411.746 54.705 412.268C66.013 411.746 76.549 409.908 86.278 405.176C96.014 400.702 104.42 394.647 111.518 387.013L236.454 249.725L111.52 112.695C103.893 105.325 95.743 99.2779 86.008 94.5449C76.279 90.0779 66.013 87.9759 54.705 87.7119ZM445.038 87.7119C433.729 87.9759 423.729 90.0779 413.993 94.5459C404.265 99.2779 395.844 105.326 388.481 112.695L264.075 249.725L388.48 387.013C395.843 394.647 404.264 400.702 413.992 405.176C423.728 409.908 433.728 411.746 445.037 412.268C456.345 411.746 466.074 409.901 475.281 405.691C485.274 401.481 492.901 395.969 499.999 388.864L373.492 249.725L500 110.33C492.902 103.489 485.275 97.9639 475.282 94.0179C466.075 90.0719 456.346 87.9769 445.038 87.7119Z" fill="#E57000"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.9 KiB |
6
auth/assets/custom-icons/icons/ripplematch.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-0.017335016280412674 1.0994987487792969 34.31733703613281 19.514122009277344">
|
||||
<g id="Homepage_ver1" fill="#000000">
|
||||
<path d="M30.7,1.3a0.5,0.5,0,0,0-.5.3L24.6,13.4,18.9,1.6a0.5,0.5,0,0,0-.5-0.3H15.3a0.3,0.3,0,0,0-.3.4l9.2,18.3a0.4,0.4,0,0,0,.6,0l0.6-1.2L31.1,7.8V20.2a0.4,0.4,0,0,0,.4.4h2.4a0.4,0.4,0,0,0,.4-0.4V1.7a0.4,0.4,0,0,0-.4-0.4H30.7Z" style="fill-rule:evenodd"></path>
|
||||
<path d="M14.3,7.5A6.4,6.4,0,0,0,8,1.1H0.3a0.3,0.3,0,0,0-.3.4L1.1,3.6a0.6,0.6,0,0,0,.5.3H8a3.5,3.5,0,0,1,3.5,3.5A3.5,3.5,0,0,1,8,11.1H5.2a0.2,0.2,0,0,0-.2.3l4.4,8.8a0.7,0.7,0,0,0,.6.4h2.6a0.3,0.3,0,0,0,.3-0.5L9.7,13.7A6.5,6.5,0,0,0,14.3,7.5Z" style="fill-rule:evenodd"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 730 B |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 18 KiB |
12
auth/assets/custom-icons/icons/upstox.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_176_150)">
|
||||
<path d="M397.756 276.664C389.302 276.867 380.894 275.355 373.04 272.219C365.186 269.083 358.049 264.389 352.059 258.419C346.069 252.449 341.351 245.328 338.188 237.484C335.026 229.641 333.486 221.238 333.661 212.783C333.661 177.106 360.315 146.907 397.71 146.83C435.06 146.83 460.011 177.06 460.011 212.768C460.011 248.475 435.152 276.664 397.787 276.664H397.756ZM402.559 111C369.568 111 347.747 123.076 333.369 141.414V115.036H293.349V389.173H333.369V281.989C347.747 300.127 369.568 312.433 402.559 312.433C457.725 312.433 500 272.137 500 212.614C500 153.076 457.725 111 402.559 111Z" fill="#5A2989"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M87.5582 218.706C104.475 206.796 118.215 190.921 127.578 172.472V224C127.578 256.071 145.148 274.608 174.871 274.608C204.594 274.608 229.468 256.102 229.468 224V115.128H269.565V308.612H229.315V284.168C222.839 294.065 204.471 312.556 168.702 312.556C115.747 312.556 87.6809 279.488 87.6809 232.517L87.6042 218.676L87.5582 218.706Z" fill="#5A2989"/>
|
||||
<path d="M0.0459128 202.026V240.849C33.7489 240.844 66.0975 227.583 90.1054 203.929C101.927 192.322 111.318 178.477 117.73 163.201C124.143 147.926 127.449 131.526 127.455 114.959H88.2027C88.1725 126.409 85.8733 137.74 81.4379 148.297C77.0025 158.853 70.5189 168.426 62.3618 176.462C45.7426 192.849 23.3393 202.033 -0.00012207 202.026H0.0459128Z" fill="#5A2989"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_176_150">
|
||||
<rect width="500" height="500" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -1,6 +1,15 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
|
||||
<path fill="none" d="m253.612 18.751 155.225 68.671 72.412 162.926-66.105 160.531-164.763 70.372-158.672-64.375-72.959-163.45L88.562 86.485l165.05-67.734Z"/>
|
||||
<path d="m261.198 1.604 155.225 68.672a18.746 18.746 0 0 1 9.548 9.532l72.413 162.924a18.752 18.752 0 0 1 .203 14.755l-66.106 160.532a18.755 18.755 0 0 1-9.973 10.103l-164.762 70.372a18.751 18.751 0 0 1-14.414.131L84.66 434.251a18.749 18.749 0 0 1-10.073-9.732L1.628 261.068a18.751 18.751 0 0 1-.177-14.877l69.814-166.94a18.744 18.744 0 0 1 10.18-10.112L246.493 1.405a18.741 18.741 0 0 1 14.705.199Zm-7.862 37.527-150.471 61.752-63.69 152.301 66.579 149.156 144.442 58.602 150.53-64.293 60.13-146.019-66.217-148.985-141.303-62.512v-.002Z"/>
|
||||
<path fill="none" d="M350.853 168.751v161.156h-24.737L250.3 257.213l-76.228 72.694h-23.957V168.751"/>
|
||||
<path d="m168.865 308.963 68.495-65.319c7.258-6.921 18.677-6.906 25.916.035l68.828 65.992v-140.92c0-10.349 8.4-18.75 18.75-18.75 10.347 0 18.75 8.401 18.75 18.75v161.156c0 10.355-8.396 18.75-18.75 18.75h-24.739a18.757 18.757 0 0 1-12.977-5.216l-62.874-60.285-63.252 60.32a18.75 18.75 0 0 1-12.94 5.181h-23.957c-10.355 0-18.75-8.395-18.75-18.75V168.751c0-10.349 8.402-18.75 18.75-18.75 10.349 0 18.75 8.401 18.75 18.75v140.212Z"/>
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_191_1078)">
|
||||
<g style="mix-blend-mode:difference">
|
||||
<path d="M261.198 1.60387L416.423 70.2759C420.678 72.1581 424.082 75.5557 425.971 79.8079L498.384 242.732C499.414 245.05 499.963 247.552 499.998 250.089C500.033 252.625 499.553 255.142 498.587 257.487L432.481 418.019C430.609 422.563 427.028 426.191 422.508 428.122L257.746 498.494C255.471 499.465 253.026 499.977 250.552 500C248.078 500.022 245.624 499.555 243.332 498.625L84.66 434.251C80.1712 432.43 76.5614 428.942 74.587 424.519L1.628 261.068C0.585027 258.731 0.0312788 256.206 0.000838817 253.648C-0.0296012 251.089 0.463911 248.551 1.451 246.191L71.265 79.2509C72.2146 76.9794 73.6024 74.9172 75.3491 73.1822C77.0958 71.4472 79.1672 70.0732 81.445 69.1389L246.493 1.40487C248.831 0.444804 251.339 -0.0324825 253.866 0.00171599C256.393 0.0359145 258.887 0.580891 261.198 1.60387ZM253.336 39.1309L102.865 100.883L39.175 253.184L105.754 402.34L250.196 460.942L400.726 396.649L460.856 250.63L394.639 101.645L253.336 39.1329V39.1309Z" fill="white"/>
|
||||
</g>
|
||||
<g style="mix-blend-mode:difference">
|
||||
<path d="M168.865 308.963L237.36 243.644C244.618 236.723 256.037 236.738 263.276 243.679L332.104 309.671V168.751C332.104 158.402 340.504 150.001 350.854 150.001C361.201 150.001 369.604 158.402 369.604 168.751V329.907C369.604 340.262 361.208 348.657 350.854 348.657H326.115C321.279 348.656 316.629 346.788 313.138 343.441L250.264 283.156L187.012 343.476C183.525 346.802 178.891 348.657 174.072 348.657H150.115C139.76 348.657 131.365 340.262 131.365 329.907V168.751C131.365 158.402 139.767 150.001 150.115 150.001C160.464 150.001 168.865 158.402 168.865 168.751V308.963Z" fill="white"/>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_191_1078">
|
||||
<rect width="500" height="500" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -1,5 +0,0 @@
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g style="mix-blend-mode:difference">
|
||||
<path d="M296.617 211.716L479.03 0H435.804L277.414 183.83L150.909 0H5L196.301 277.983L5 500H48.2286L215.492 305.869L349.091 500H495L296.606 211.716H296.617ZM237.409 280.432L218.026 252.752L63.8045 32.492H130.201L254.66 210.249L274.043 237.929L435.824 468.986H369.428L237.409 280.443V280.432Z" fill="white"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 458 B |
@@ -82,9 +82,9 @@ PODS:
|
||||
- qr_code_scanner (0.2.0):
|
||||
- Flutter
|
||||
- MTBBarcodeScanner
|
||||
- SDWebImage (5.19.2):
|
||||
- SDWebImage/Core (= 5.19.2)
|
||||
- SDWebImage/Core (5.19.2)
|
||||
- SDWebImage (5.19.7):
|
||||
- SDWebImage/Core (= 5.19.7)
|
||||
- SDWebImage/Core (5.19.7)
|
||||
- Sentry/HybridSDK (8.33.0)
|
||||
- sentry_flutter (8.7.0):
|
||||
- Flutter
|
||||
@@ -100,16 +100,16 @@ PODS:
|
||||
- sqflite (0.0.3):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- "sqlite3 (3.46.0+1)":
|
||||
- "sqlite3/common (= 3.46.0+1)"
|
||||
- "sqlite3/common (3.46.0+1)"
|
||||
- "sqlite3/dbstatvtab (3.46.0+1)":
|
||||
- "sqlite3 (3.46.1+1)":
|
||||
- "sqlite3/common (= 3.46.1+1)"
|
||||
- "sqlite3/common (3.46.1+1)"
|
||||
- "sqlite3/dbstatvtab (3.46.1+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/fts5 (3.46.0+1)":
|
||||
- "sqlite3/fts5 (3.46.1+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/perf-threadsafe (3.46.0+1)":
|
||||
- "sqlite3/perf-threadsafe (3.46.1+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/rtree (3.46.0+1)":
|
||||
- "sqlite3/rtree (3.46.1+1)":
|
||||
- sqlite3/common
|
||||
- sqlite3_flutter_libs (0.0.1):
|
||||
- Flutter
|
||||
@@ -245,14 +245,14 @@ SPEC CHECKSUMS:
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
privacy_screen: 1a131c052ceb3c3659934b003b0d397c2381a24e
|
||||
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
|
||||
SDWebImage: dfe95b2466a9823cf9f0c6d01217c06550d7b29a
|
||||
SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3
|
||||
Sentry: 8560050221424aef0bebc8e31eedf00af80f90a6
|
||||
sentry_flutter: e26b861f744e5037a3faf9bf56603ec65d658a61
|
||||
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sodium_libs: 1faae17af662384acbd13e41867a0008cd2e2318
|
||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||
sqlite3: 292c3e1bfe89f64e51ea7fc7dab9182a017c8630
|
||||
sqlite3: 0bb0e6389d824e40296f531b858a2a0b71c0d2fb
|
||||
sqlite3_flutter_libs: c00457ebd31e59fa6bb830380ddba24d44fbcd3b
|
||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
|
||||
|
||||
@@ -66,24 +66,25 @@ final lightThemeData = ThemeData(
|
||||
color: Colors.black,
|
||||
width: 2,
|
||||
),
|
||||
fillColor: MaterialStateProperty.resolveWith((states) {
|
||||
return states.contains(MaterialState.selected)
|
||||
fillColor: WidgetStateProperty.resolveWith((states) {
|
||||
return states.contains(WidgetState.selected)
|
||||
? const Color.fromRGBO(0, 0, 0, 1)
|
||||
: const Color.fromRGBO(255, 255, 255, 1);
|
||||
}),
|
||||
checkColor: MaterialStateProperty.resolveWith((states) {
|
||||
return states.contains(MaterialState.selected)
|
||||
checkColor: WidgetStateProperty.resolveWith((states) {
|
||||
return states.contains(WidgetState.selected)
|
||||
? const Color.fromRGBO(255, 255, 255, 1)
|
||||
: const Color.fromRGBO(0, 0, 0, 1);
|
||||
}),
|
||||
),
|
||||
|
||||
radioTheme: RadioThemeData(
|
||||
fillColor:
|
||||
MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const Color.fromRGBO(102, 187, 106, 1);
|
||||
}
|
||||
return null;
|
||||
@@ -91,21 +92,21 @@ final lightThemeData = ThemeData(
|
||||
),
|
||||
switchTheme: SwitchThemeData(
|
||||
thumbColor:
|
||||
MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const Color.fromRGBO(102, 187, 106, 1);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
trackColor:
|
||||
MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const Color.fromRGBO(102, 187, 106, 1);
|
||||
}
|
||||
return null;
|
||||
@@ -114,7 +115,7 @@ final lightThemeData = ThemeData(
|
||||
colorScheme: const ColorScheme.light(
|
||||
primary: Colors.black,
|
||||
secondary: Color.fromARGB(255, 163, 163, 163),
|
||||
).copyWith(background: const Color.fromRGBO(255, 255, 255, 1)),
|
||||
).copyWith(surface: const Color.fromRGBO(255, 255, 255, 1)),
|
||||
);
|
||||
|
||||
final darkThemeData = ThemeData(
|
||||
@@ -176,15 +177,15 @@ final darkThemeData = ThemeData(
|
||||
color: Colors.grey,
|
||||
width: 2,
|
||||
),
|
||||
fillColor: MaterialStateProperty.resolveWith((states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
fillColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const Color.fromRGBO(158, 158, 158, 1);
|
||||
} else {
|
||||
return const Color.fromRGBO(0, 0, 0, 1);
|
||||
}
|
||||
}),
|
||||
checkColor: MaterialStateProperty.resolveWith((states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
checkColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const Color.fromRGBO(0, 0, 0, 1);
|
||||
} else {
|
||||
return const Color.fromRGBO(158, 158, 158, 1);
|
||||
@@ -193,11 +194,11 @@ final darkThemeData = ThemeData(
|
||||
),
|
||||
radioTheme: RadioThemeData(
|
||||
fillColor:
|
||||
MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const Color.fromRGBO(102, 187, 106, 1);
|
||||
}
|
||||
return null;
|
||||
@@ -205,28 +206,28 @@ final darkThemeData = ThemeData(
|
||||
),
|
||||
switchTheme: SwitchThemeData(
|
||||
thumbColor:
|
||||
MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const Color.fromRGBO(102, 187, 106, 1);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
trackColor:
|
||||
MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
WidgetStateProperty.resolveWith<Color?>((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return null;
|
||||
}
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return const Color.fromRGBO(102, 187, 106, 1);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
),
|
||||
colorScheme: const ColorScheme.dark(primary: Colors.white)
|
||||
.copyWith(background: const Color.fromRGBO(0, 0, 0, 1)),
|
||||
.copyWith(surface: const Color.fromRGBO(0, 0, 0, 1)),
|
||||
);
|
||||
|
||||
TextTheme _buildTextTheme(Color textColor) {
|
||||
@@ -458,17 +459,17 @@ OutlinedButtonThemeData buildOutlinedButtonThemeData({
|
||||
fontSize: 18,
|
||||
),
|
||||
).copyWith(
|
||||
backgroundColor: MaterialStateProperty.resolveWith<Color>(
|
||||
(Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
backgroundColor: WidgetStateProperty.resolveWith<Color>(
|
||||
(Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return bgDisabled;
|
||||
}
|
||||
return bgEnabled;
|
||||
},
|
||||
),
|
||||
foregroundColor: MaterialStateProperty.resolveWith<Color>(
|
||||
(Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.disabled)) {
|
||||
foregroundColor: WidgetStateProperty.resolveWith<Color>(
|
||||
(Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return fgDisabled;
|
||||
}
|
||||
return fgEnabled;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"account": "حسابي",
|
||||
"account": "الحساب",
|
||||
"unlock": "فتح القفل",
|
||||
"recoveryKey": "مفتاح الاسترداد",
|
||||
"counterAppBarTitle": "العداد",
|
||||
@@ -19,6 +19,20 @@
|
||||
"pleaseVerifyDetails": "من فضلك تأكد من بياناتك وحاول مرة أخرى",
|
||||
"codeIssuerHint": "المصدِّر",
|
||||
"codeSecretKeyHint": "الرمز السري",
|
||||
"secret": "سري",
|
||||
"all": "الكل",
|
||||
"notes": "ملاحظات",
|
||||
"notesLengthLimit": "يمكن أن تصل الملاحظات إلى {count} حرفا كحد أقصى",
|
||||
"@notesLengthLimit": {
|
||||
"description": "Text to indicate the maximum number of characters allowed for notes",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"description": "The maximum number of characters allowed for notes",
|
||||
"type": "int",
|
||||
"example": "100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codeAccountHint": "الحساب (you@domain.com)",
|
||||
"codeTagHint": "وسم",
|
||||
"accountKeyType": "نوع المفتاح",
|
||||
@@ -79,7 +93,7 @@
|
||||
"data": "البيانات",
|
||||
"importCodes": "استورد شيفرات",
|
||||
"importTypePlainText": "نص بسيط",
|
||||
"importTypeEnteEncrypted": "تصدير Ente Ecrypted",
|
||||
"importTypeEnteEncrypted": "تصدير مشفر ente",
|
||||
"passwordForDecryptingExport": "كلمة المرور لفك تشفير التصدير",
|
||||
"passwordEmptyError": "لا يمكن أن تكون كلمة المرور فارغة",
|
||||
"importFromApp": "استورد الشيفرات من {appName}",
|
||||
@@ -137,7 +151,6 @@
|
||||
"leaveFamily": "مغادرة خطة العائلة",
|
||||
"leaveFamilyMessage": "هل أنت متأكد من الخروج من خطة العائلة؟",
|
||||
"inFamilyPlanMessage": "أنت مندرج ضمن خطة عائلية!",
|
||||
"swipeHint": "اسحب لليسار لتحرير أو إزالة الرموز",
|
||||
"scan": "مسح",
|
||||
"scanACode": "فحص رمز Qr",
|
||||
"verify": "التحقق",
|
||||
@@ -182,6 +195,7 @@
|
||||
"security": "الأمان",
|
||||
"lockscreen": "شاشة القفل",
|
||||
"authToChangeLockscreenSetting": "الرجاء المصادقة لتغيير إعدادات شاشة القفل",
|
||||
"deviceLockEnablePreSteps": "لتمكين قفل التطبيق، فضلا أعد شيفرة مرور للجهاز أو قفل الشاشة في إعدادات نظامك.",
|
||||
"viewActiveSessions": "عرض الجلسات النشطة",
|
||||
"authToViewYourActiveSessions": "الرجاء المصادقة لعرض جلساتك النشطة",
|
||||
"searchHint": "بحث...",
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
"pleaseWait": "Моля изчакайте...",
|
||||
"generatingEncryptionKeysTitle": "Генерират се ключове за шифроване...",
|
||||
"recreatePassword": "Създайте отново парола",
|
||||
"recreatePasswordMessage": "Текущото устройство не е достатъчно мощно, за да потвърди паролата Ви, така че трябва да го генерираме отново веднъж по начин, който работи с всички устройства. \n\nВлезте с Вашия ключ за възстановяване и генерирайте отново паролата си (можете да използвате същата отново, ако желаете).",
|
||||
"recreatePasswordMessage": "Текущото устройство не е достатъчно мощно, за да потвърди паролата Ви, така че трябва да го генерираме отново веднъж по начин, който работи с всички устройства. \n\nМоля, влезте с Вашия ключ за възстановяване и генерирайте отново паролата си (можете да използвате същата отново, ако желаете).",
|
||||
"useRecoveryKey": "Използвайте ключ за възстановяване",
|
||||
"incorrectPasswordTitle": "Грешна парола",
|
||||
"welcomeBack": "Добре дошли отново!",
|
||||
@@ -130,7 +130,60 @@
|
||||
"faq_q_3": "Как мога да изтрия кодове?",
|
||||
"faq_a_3": "Можете да изтриете код, като плъзнете наляво върху него.",
|
||||
"faq_q_4": "Как мога да подкрепя този проект?",
|
||||
"faq_a_4": "Можете да подкрепите развитието на този проект, като се абонирате за нашето приложение за снимки @ ente.io.",
|
||||
"faq_q_5": "Как мога да активирам заключване чрез FaceID в Auth",
|
||||
"faq_a_5": "Можете да активирате заключване чрез FaceID в Настройки → Сигурност → Заключен екран.",
|
||||
"somethingWentWrongMessage": "Нещо се обърка, моля опитайте отново",
|
||||
"leaveFamily": "Напуснете семейството",
|
||||
"leaveFamilyMessage": "Сигурни ли сте, че искате да напуснете семейния план?",
|
||||
"inFamilyPlanMessage": "Вие сте на семеен план!",
|
||||
"scan": "Сканиране",
|
||||
"scanACode": "Скениране на код",
|
||||
"verify": "Потвърждаване",
|
||||
"verifyEmail": "Потвърдете имейла",
|
||||
"enterCodeHint": "Въведете 6-цифрения код от\nВашето приложение за удостоверяване",
|
||||
"lostDeviceTitle": "Загубено устройство?",
|
||||
"twoFactorAuthTitle": "Двуфакторно удостоверяване",
|
||||
"passkeyAuthTitle": "Удостоверяване с ключ за парола",
|
||||
"verifyPasskey": "Потвърдете ключ за парола",
|
||||
"recoverAccount": "Възстановяване на акаунт",
|
||||
"enterRecoveryKeyHint": "Въведете Вашия ключ за възстановяване",
|
||||
"recover": "Възстановяване",
|
||||
"contactSupportViaEmailMessage": "Моля, изпратете имейл до {email} от Вашия регистриран имейл адрес",
|
||||
"@contactSupportViaEmailMessage": {
|
||||
"placeholders": {
|
||||
"email": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"invalidQRCode": "Невалиден QR код",
|
||||
"noRecoveryKeyTitle": "Няма ключ за възстановяване?",
|
||||
"enterEmailHint": "Въведете Вашият имейл адрес",
|
||||
"invalidEmailTitle": "Невалиден имейл адрес",
|
||||
"invalidEmailMessage": "Моля, въведете валиден имейл адрес.",
|
||||
"deleteAccount": "Изтриване на акаунта",
|
||||
"deleteAccountQuery": "Ще съжаляваме да си тръгнете. Изправени ли сте пред някакъв проблем?",
|
||||
"yesSendFeedbackAction": "Да, изпращане на обратна връзка",
|
||||
"noDeleteAccountAction": "Не, изтриване на акаунта",
|
||||
"initiateAccountDeleteTitle": "Моля, удостоверете се, за да инициирате изтриването на акаунта",
|
||||
"sendEmail": "Изпратете имейл",
|
||||
"createNewAccount": "Създаване на нов акаунт",
|
||||
"weakStrength": "Слаба",
|
||||
"strongStrength": "Силна",
|
||||
"moderateStrength": "Умерена",
|
||||
"confirmPassword": "Потвърждаване на паролата",
|
||||
"close": "Затваряне",
|
||||
"oopsSomethingWentWrong": "Ами сега, нещо се обърка.",
|
||||
"selectLanguage": "Изберете език",
|
||||
"language": "Език",
|
||||
"social": "Социални мрежи",
|
||||
"security": "Сигурност",
|
||||
"lockscreen": "Заключен екран",
|
||||
"authToChangeLockscreenSetting": "Моля, удостоверете се, за да промените настройката за заключен екран",
|
||||
"deviceLockEnablePreSteps": "За да активирате заключването на устройството, моля, задайте парола за устройството или заключване на екрана в системните настройки.",
|
||||
"viewActiveSessions": "Вижте активните сесии",
|
||||
"authToViewYourActiveSessions": "Моля, удостоверете се, за да видите Вашите активни сесии",
|
||||
"searchHint": "Търсене...",
|
||||
"search": "Търсене",
|
||||
"sorryUnableToGenCode": "За съжаление не може да се генерира код за {issuerName}",
|
||||
@@ -183,46 +236,118 @@
|
||||
"insecureDevice": "Несигурно устройство",
|
||||
"sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "За съжаление не можахме да генерираме защитени ключове на това устройство.\n\nМоля, регистрирайте се от друго устройство.",
|
||||
"howItWorks": "Как работи",
|
||||
"ackPasswordLostWarning": "Разбирам, че ако загубя паролата си, може да загубя данните си, тъй като данните ми са <underline>шифровани от край до край</underline>.",
|
||||
"loginTerms": "С натискането на вход, се съгласявам с <u-terms>условията за ползване</u-terms> и <u-policy>политиката за поверителност</u-policy>",
|
||||
"logInLabel": "Вход",
|
||||
"logout": "Изход",
|
||||
"areYouSureYouWantToLogout": "Наистина ли искате да излезете от профила си?",
|
||||
"yesLogout": "Да, излез",
|
||||
"exit": "Изход",
|
||||
"verifyingRecoveryKey": "Проверка на ключа за възстановяване...",
|
||||
"recoveryKeyVerified": "Ключът за възстановяване е проверен",
|
||||
"recoveryKeySuccessBody": "Страхотно! Вашият ключ за възстановяване е валиден. Благодарим Ви за проверката.\n\nМоля, не забравяйте да запазите безопасно архивирания си ключ за възстановяване.",
|
||||
"invalidRecoveryKey": "Въведеният от Вас ключ за възстановяване не е валиден. Моля, уверете се, че съдържа 24 думи и проверете правописа на всяка.\n\nАко сте въвели по-стар код за възстановяване, уверете се, че е дълъг 64 знака и проверете всеки от тях.",
|
||||
"recreatePasswordTitle": "Създайте отново парола",
|
||||
"recreatePasswordBody": "Текущото устройство не е достатъчно мощно, за да потвърди паролата Ви, но можем да я регенерираме по начин, който работи с всички устройства.\n\nМоля, влезте с Вашия ключ за възстановяване и генерирайте отново паролата си (можете да използвате същата отново, ако желаете).",
|
||||
"invalidKey": "Невалиден ключ",
|
||||
"tryAgain": "Опитайте отново",
|
||||
"viewRecoveryKey": "Вижте ключа за възстановяване",
|
||||
"confirmRecoveryKey": "Потвърдете ключа за възстановяване",
|
||||
"recoveryKeyVerifyReason": "Вашият ключ за възстановяване е единственият начин да възстановите Вашите снимки, ако забравите паролата си. Можете да намерите своя ключ за възстановяване в Настройки > Акаунт.\n\nМоля, въведете Вашия ключ за възстановяване тук, за да проверите дали сте го запазили правилно.",
|
||||
"confirmYourRecoveryKey": "Потвърдете Вашия ключ за възстановяване",
|
||||
"confirm": "Потвърждаване",
|
||||
"emailYourLogs": "Изпратете Вашата история на действията на имейл",
|
||||
"pleaseSendTheLogsTo": "Моля, изпратете историята на действията на \n{toEmail}",
|
||||
"copyEmailAddress": "Копиране на имейл адрес",
|
||||
"exportLogs": "Експорт на файловете с историята",
|
||||
"enterYourRecoveryKey": "Въведете Вашия ключ за възстановяване",
|
||||
"tempErrorContactSupportIfPersists": "Изглежда нещо се обърка. Моля, опитайте отново след известно време. Ако грешката продължава, моля, свържете се с нашия екип за поддръжка.",
|
||||
"networkHostLookUpErr": "Не може да се свърже с Ente, моля, проверете мрежовите си настройки и се свържете с поддръжката, ако проблемът продължава.",
|
||||
"networkConnectionRefusedErr": "Не може да се свърже с Ente, моля, опитайте отново след известно време. Ако проблемът продължава, моля, свържете се с поддръжката.",
|
||||
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Изглежда нещо се обърка. Моля, опитайте отново след известно време. Ако грешката продължава, моля, свържете се с нашия екип за поддръжка.",
|
||||
"about": "Относно",
|
||||
"weAreOpenSource": "Ние сме с отворен код!",
|
||||
"privacy": "Поверителност",
|
||||
"terms": "Условия",
|
||||
"checkForUpdates": "Провери за актуализации",
|
||||
"checkStatus": "Проверка на състоянието",
|
||||
"downloadUpdate": "Изтегляне",
|
||||
"criticalUpdateAvailable": "Налична е критична актуализация",
|
||||
"updateAvailable": "Налична актуализация",
|
||||
"update": "Актуализиране",
|
||||
"checking": "Извършва се проверка...",
|
||||
"youAreOnTheLatestVersion": "Вие сте с най-новата версия",
|
||||
"warning": "Предупреждение",
|
||||
"exportWarningDesc": "Експортираният файл съдържа поверителна информация. Моля, съхранявайте го безопасно.",
|
||||
"iUnderStand": "Разбрах",
|
||||
"@iUnderStand": {
|
||||
"description": "Text for the button to confirm the user understands the warning"
|
||||
},
|
||||
"authToExportCodes": "Моля, удостоверете се, за да експортирате Вашите кодове",
|
||||
"importSuccessTitle": "Ура!",
|
||||
"importSuccessDesc": "Импортирахте {count} кода!",
|
||||
"@importSuccessDesc": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"description": "The number of codes imported",
|
||||
"type": "int",
|
||||
"example": "1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sorry": "Съжаляваме",
|
||||
"importFailureDesc": "Неуспешен анализ на избрания файл.\nМоля, пишете на support@ente.io, ако имате нужда от помощ!",
|
||||
"pendingSyncs": "Предупреждение",
|
||||
"pendingSyncsWarningBody": "Някои от вашите кодове не са архивирани.\n\nМоля, уверете се, че имате резервно копие на тези кодове, преди да излезете.",
|
||||
"checkInboxAndSpamFolder": "Моля, проверете входящата си поща (и спама), за да завършите проверката",
|
||||
"tapToEnterCode": "Докоснете, за да въведете код",
|
||||
"resendEmail": "Повторно изпращане на имейл",
|
||||
"weHaveSendEmailTo": "Изпратихме имейл до <green>{email}</green>",
|
||||
"@weHaveSendEmailTo": {
|
||||
"description": "Text to indicate that we have sent a mail to the user",
|
||||
"placeholders": {
|
||||
"email": {
|
||||
"description": "The email address of the user",
|
||||
"type": "String",
|
||||
"example": "example@ente.io"
|
||||
}
|
||||
}
|
||||
},
|
||||
"activeSessions": "Активни сесии",
|
||||
"somethingWentWrongPleaseTryAgain": "Нещо се обърка, моля опитайте отново",
|
||||
"thisWillLogYouOutOfThisDevice": "Това ще Ви изкара от профила на това устройство!",
|
||||
"thisWillLogYouOutOfTheFollowingDevice": "Това ще Ви изкара от профила на следното устройство:",
|
||||
"terminateSession": "Прекратяване на сесията?",
|
||||
"terminate": "Прекратяване",
|
||||
"thisDevice": "Това устройство",
|
||||
"toResetVerifyEmail": "За да нулирате паролата си, моля, първо потвърдете своя имейл.",
|
||||
"thisEmailIsAlreadyInUse": "Този имейл вече се използва",
|
||||
"verificationFailedPleaseTryAgain": "Неуспешно проверка, моля опитайте отново",
|
||||
"yourVerificationCodeHasExpired": "Вашият код за потвърждение е изтекъл",
|
||||
"incorrectCode": "Неправилен код",
|
||||
"sorryTheCodeYouveEnteredIsIncorrect": "За съжаление кодът, който сте въвели, е неправилен",
|
||||
"emailChangedTo": "Имейлът е променен на {newEmail}",
|
||||
"authenticationFailedPleaseTryAgain": "Неуспешно удостоверяване, моля опитайте отново",
|
||||
"authenticationSuccessful": "Успешно удостоверяване!",
|
||||
"twofactorAuthenticationSuccessfullyReset": "Двуфакторното удостоверяване бе успешно нулирано",
|
||||
"incorrectRecoveryKey": "Неправилен ключ за възстановяване",
|
||||
"theRecoveryKeyYouEnteredIsIncorrect": "Въведеният от Вас ключ за възстановяване е неправилен",
|
||||
"enterPassword": "Въведете парола",
|
||||
"selectExportFormat": "Изберете формат за експортиране",
|
||||
"exportDialogDesc": "Шифрованите експорти ще бъдат защитени с парола по Ваш избор.",
|
||||
"encrypted": "Шифровано",
|
||||
"plainText": "Обикновен текст",
|
||||
"passwordToEncryptExport": "Парола за шифроване на експортирането",
|
||||
"export": "Експортиране",
|
||||
"useOffline": "Използвайте без резервни копия",
|
||||
"signInToBackup": "Влезте, за да архивирате Вашите кодове",
|
||||
"singIn": "Вход",
|
||||
"sigInBackupReminder": "Моля, експортирайте Вашите кодове, за да сте сигурни, че имате резервно копие, от което можете да ги възстановите.",
|
||||
"offlineModeWarning": "Избрахте да продължите без резервни копия. Моля, направете ръчни резервни копия, за да сте сигурни, че Вашите кодове са в безопасност.",
|
||||
"showLargeIcons": "Показване на големи икони",
|
||||
"shouldHideCode": "Скриване на кодове",
|
||||
"doubleTapToViewHiddenCode": "Можете да докоснете два пъти върху запис, за да видите кода",
|
||||
"focusOnSearchBar": "Фокусиране на търсенето при стартиране на приложението",
|
||||
"confirmUpdatingkey": "Сигурни ли сте, че искате да актуализирате секретния ключ?",
|
||||
"minimizeAppOnCopy": "Минимизиране на приложението при копиране",
|
||||
"editCodeAuthMessage": "Удостоверете се, за да редактирате кода",
|
||||
|
||||
@@ -16,12 +16,26 @@
|
||||
"secretCanNotBeEmpty": "Geheimnis darf nicht leer sein",
|
||||
"bothIssuerAndAccountCanNotBeEmpty": "Sowohl Aussteller als auch Konto können nicht leer sein",
|
||||
"incorrectDetails": "Falsche Angaben",
|
||||
"pleaseVerifyDetails": "Überprüfe die Angaben und versuche es erneut",
|
||||
"pleaseVerifyDetails": "Bitte überprüfen Sie die Details und versuchen Sie es erneut",
|
||||
"codeIssuerHint": "Aussteller",
|
||||
"codeSecretKeyHint": "Geheimer Schlüssel",
|
||||
"secret": "Geheimnis",
|
||||
"all": "Alle",
|
||||
"notes": "Notizen",
|
||||
"notesLengthLimit": "Notizen können maximal {count} Zeichen lang sein",
|
||||
"@notesLengthLimit": {
|
||||
"description": "Text to indicate the maximum number of characters allowed for notes",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"description": "The maximum number of characters allowed for notes",
|
||||
"type": "int",
|
||||
"example": "100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codeAccountHint": "Konto (you@domain.com)",
|
||||
"codeTagHint": "Tag",
|
||||
"accountKeyType": "Art des Keys",
|
||||
"accountKeyType": "Art des Schlüssels",
|
||||
"sessionExpired": "Sitzung abgelaufen",
|
||||
"@sessionExpired": {
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
@@ -34,6 +48,9 @@
|
||||
"nextTotpTitle": "Nächster Code",
|
||||
"deleteCodeTitle": "Code löschen?",
|
||||
"deleteCodeMessage": "Sind Sie sicher, dass Sie diesen Code löschen wollen? Diese Aktion ist unumkehrbar.",
|
||||
"trashCode": "Code löschen?",
|
||||
"trashCodeMessage": "Sind Sie sicher, dass Sie den Code für {account} löschen wollen?",
|
||||
"trash": "Papierkorb",
|
||||
"viewLogsAction": "Protokolle anzeigen",
|
||||
"sendLogsDescription": "Dadurch werden Protokolle übermittelt, die uns bei der Behebung Ihres Problems helfen. Obwohl wir Vorkehrungen treffen, um sicherzustellen, dass keine sensiblen Informationen protokolliert werden, empfehlen wir Ihnen, diese Protokolle anzusehen, bevor Sie sie weitergeben.",
|
||||
"preparingLogsTitle": "Vorbereiten der Protokolle...",
|
||||
@@ -48,9 +65,9 @@
|
||||
},
|
||||
"copyEmailAction": "E-Mail kopieren",
|
||||
"exportLogsAction": "Protokolle exportieren",
|
||||
"reportABug": "Fehlermelden",
|
||||
"reportABug": "Einen Fehler melden",
|
||||
"crashAndErrorReporting": "Absturz- und Fehlerberichte",
|
||||
"reportBug": "Fehlermelden",
|
||||
"reportBug": "Fehler melden",
|
||||
"emailUsMessage": "Bitte senden Sie uns eine E-Mail an {email}",
|
||||
"@emailUsMessage": {
|
||||
"placeholders": {
|
||||
@@ -60,7 +77,7 @@
|
||||
}
|
||||
},
|
||||
"contactSupport": "Support kontaktieren",
|
||||
"rateUsOnStore": "Bewerte uns auf {storeName}",
|
||||
"rateUsOnStore": "Bewerten Sie uns auf {storeName}",
|
||||
"blog": "Blog",
|
||||
"merchandise": "Merchandise",
|
||||
"verifyPassword": "Passwort überprüfen",
|
||||
@@ -72,8 +89,8 @@
|
||||
"incorrectPasswordTitle": "Falsches Passwort",
|
||||
"welcomeBack": "Willkommen zurück!",
|
||||
"madeWithLoveAtPrefix": "gemacht mit ❤️ bei ",
|
||||
"supportDevs": "Bei <bold-green>ente</bold-green> registrieren um das Projekt zu unterstützen.",
|
||||
"supportDiscount": "Benutze den Rabattcode \"AUTH\" für 10% Rabatt im ersten Jahr",
|
||||
"supportDevs": "Bei <bold-green>ente</bold-green> registrieren, um das Projekt zu unterstützen",
|
||||
"supportDiscount": "Benutzen Sie den Rabattcode \"AUTH\" für 10 % Rabatt im ersten Jahr",
|
||||
"changeEmail": "E-Mail ändern",
|
||||
"changePassword": "Passwort ändern",
|
||||
"data": "Datei",
|
||||
@@ -100,6 +117,7 @@
|
||||
"emailVerificationToggle": "E-Mail-Verifizierung",
|
||||
"emailVerificationEnableWarning": "Stellen Sie sicher, eine Kopie Ihrer Zwei-Faktor-Authentifizierung an anderer Stelle zu speichern, um zu vermeiden, dass Sie sich versehentlich aus Ihrem Account aussperren.",
|
||||
"authToChangeEmailVerificationSetting": "Bitte Authentifizieren um die E-Mail Bestätigung zu ändern",
|
||||
"authenticateGeneric": "Bitte authentifizieren",
|
||||
"authToViewYourRecoveryKey": "Bitte authentifizieren um ihren Wiederherstellungscode anzuzeigen",
|
||||
"authToChangeYourEmail": "Bitte authentifizieren um ihre Emailadresse zu ändern",
|
||||
"authToChangeYourPassword": "Bitte authentifizieren um ihr Passwort zu ändern",
|
||||
@@ -137,7 +155,6 @@
|
||||
"leaveFamily": "Familie verlassen",
|
||||
"leaveFamilyMessage": "Sind Sie sicher, dass Sie den Familien-Plan verlassen wollen?",
|
||||
"inFamilyPlanMessage": "Sie haben einen Familien-Plan!",
|
||||
"swipeHint": "Wischen Sie nach links, um Codes zu bearbeiten oder zu entfernen",
|
||||
"scan": "Scannen",
|
||||
"scanACode": "Scan einen Code",
|
||||
"verify": "Überprüfen Sie",
|
||||
@@ -164,7 +181,7 @@
|
||||
"invalidEmailTitle": "Ungültige E-Mail Adresse",
|
||||
"invalidEmailMessage": "Bitte geben Sie eine gültige E-Mail Adresse ein.",
|
||||
"deleteAccount": "Konto löschen",
|
||||
"deleteAccountQuery": "Es wird uns leid tun, Sie gehen zu sehen. Haben Sie ein Problem?",
|
||||
"deleteAccountQuery": "Es tut uns leid, dass Sie gehen. Haben Sie ein Problem?",
|
||||
"yesSendFeedbackAction": "Ja, Feedback senden",
|
||||
"noDeleteAccountAction": "Nein, Konto löschen",
|
||||
"initiateAccountDeleteTitle": "Bitte authentifizieren Sie sich, um die Kontolöschung einzuleiten",
|
||||
@@ -182,6 +199,7 @@
|
||||
"security": "Sicherheit",
|
||||
"lockscreen": "Sperrbildschirm",
|
||||
"authToChangeLockscreenSetting": "Bitte authentifizieren um die Einstellungen des Sperrbildschirms zu ändern",
|
||||
"deviceLockEnablePreSteps": "Um die Gerätesperre zu aktivieren, richte bitte einen Gerätepasscode oder eine Bildschirmsperre in den Systemeinstellungen ein.",
|
||||
"viewActiveSessions": "Aktive Sitzungen anzeigen",
|
||||
"authToViewYourActiveSessions": "Bitte authentifizieren um, die aktiven Sitzungen zu sehen",
|
||||
"searchHint": "Suchen...",
|
||||
@@ -192,6 +210,10 @@
|
||||
"scanAQrCode": "QR-Code scannen",
|
||||
"enterDetailsManually": "Details manuell hinzufügen",
|
||||
"edit": "Editieren",
|
||||
"share": "Teilen",
|
||||
"shareCodes": "Codes teilen",
|
||||
"shareCodesDuration": "Wählen Sie die Dauer aus, für die Sie die Codes teilen möchten.",
|
||||
"restore": "Wiederherstellen",
|
||||
"copiedToClipboard": "In die Zwischenablage kopieren",
|
||||
"copiedNextToClipboard": "Nächster Code wurde in die Zwischenablage kopiert",
|
||||
"error": "Fehler",
|
||||
@@ -345,6 +367,7 @@
|
||||
"sigInBackupReminder": "Bitte exportieren Sie Ihre Codes, um sicherzustellen, dass Sie ein Backup haben, aus dem Sie wiederherstellen können.",
|
||||
"offlineModeWarning": "Sie haben sich dafür entschieden, ohne Sicherungen fortzufahren. Bitte führen Sie manuelle Sicherungen durch, um sicherzustellen, dass Ihre Codes sicher sind.",
|
||||
"showLargeIcons": "Große Symbole anzeigen",
|
||||
"compactMode": "Kompaktmodus",
|
||||
"shouldHideCode": "Codes ausblenden",
|
||||
"doubleTapToViewHiddenCode": "Sie können auf einen Eintrag doppelt tippen, um den Code anzuzeigen",
|
||||
"focusOnSearchBar": "Suche bei App-Start automatisch öffnen",
|
||||
@@ -441,5 +464,31 @@
|
||||
"deleteTagTitle": "Tag löschen?",
|
||||
"deleteTagMessage": "Sind Sie sicher, dass Sie diesen Code löschen wollen? Diese Aktion ist unumkehrbar.",
|
||||
"somethingWentWrongParsingCode": "Wir konnten {x} Codes nicht parsen.",
|
||||
"updateNotAvailable": "Update ist nicht verfügbar"
|
||||
"updateNotAvailable": "Update ist nicht verfügbar",
|
||||
"viewRawCodes": "Rohcodes anzeigen",
|
||||
"rawCodes": "Rohcodes",
|
||||
"rawCodeData": "Rohcode Daten",
|
||||
"appLock": "App-Sperre",
|
||||
"noSystemLockFound": "Keine Systemsperre gefunden",
|
||||
"toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Um die App-Sperre zu aktivieren, konfiguriere bitte den Gerätepasscode oder die Bildschirmsperre in den Systemeinstellungen.",
|
||||
"autoLock": "Automatisches Sperren",
|
||||
"immediately": "Sofort",
|
||||
"reEnterPassword": "Passwort erneut eingeben",
|
||||
"reEnterPin": "PIN erneut eingeben",
|
||||
"next": "Weiter",
|
||||
"tooManyIncorrectAttempts": "Zu viele fehlerhafte Versuche",
|
||||
"tapToUnlock": "Zum Entsperren antippen",
|
||||
"setNewPassword": "Neues Passwort festlegen",
|
||||
"deviceLock": "Gerätesperre",
|
||||
"hideContent": "Inhalte verstecken",
|
||||
"hideContentDescriptionAndroid": "Versteckt Inhalte der App beim Wechseln zwischen Apps und deaktiviert Screenshots",
|
||||
"hideContentDescriptioniOS": "Versteckt Inhalte der App beim Wechseln zwischen Apps",
|
||||
"autoLockFeatureDescription": "Zeit, nach der die App gesperrt wird, nachdem sie in den Hintergrund verschoben wurde",
|
||||
"appLockDescription": "Wähle zwischen dem Standard-Sperrbildschirm deines Gerätes und einem eigenen Sperrbildschirm mit PIN oder Passwort.",
|
||||
"pinLock": "PIN-Sperre",
|
||||
"enterPin": "PIN eingeben",
|
||||
"setNewPin": "Neue PIN festlegen",
|
||||
"importFailureDescNew": "Die ausgewählte Datei konnte nicht verarbeitet werden.",
|
||||
"appLockNotEnabled": "App-Sperre nicht aktiviert",
|
||||
"appLockNotEnabledDescription": "Bitte aktivieren Sie die App-Sperre über Security > App-Sperre"
|
||||
}
|
||||
@@ -137,7 +137,6 @@
|
||||
"leaveFamily": "Αποχώρηση από οικογένεια",
|
||||
"leaveFamilyMessage": "Είστε σίγουροι ότι θέλετε να φύγετε από το οικογενειακό πρόγραμμα;",
|
||||
"inFamilyPlanMessage": "Είστε σε οικογενειακό πρόγραμμα!",
|
||||
"swipeHint": "Σύρετε αριστερά για επεξεργασία ή αφαίρεση κωδικών",
|
||||
"scan": "Σάρωση",
|
||||
"scanACode": "Σάρωση κωδικού",
|
||||
"verify": "Επαλήθευση",
|
||||
@@ -182,6 +181,7 @@
|
||||
"security": "Ασφάλεια",
|
||||
"lockscreen": "Οθόνη κλειδώματος",
|
||||
"authToChangeLockscreenSetting": "Παρακαλώ πραγματοποιήστε έλεγχο ταυτότητας για να αλλάξετε τις ρυθμίσεις οθόνης κλειδώματος",
|
||||
"deviceLockEnablePreSteps": "Για να ενεργοποιήσετε το κλείδωμα της συσκευής, παρακαλώ ρυθμίστε τον κωδικό πρόσβασης της συσκευής ή το κλείδωμα οθόνης στις ρυθμίσεις του συστήματός σας.",
|
||||
"viewActiveSessions": "Προβολή ενεργών συνεδριών",
|
||||
"authToViewYourActiveSessions": "Παρακαλώ πραγματοποιήστε έλεγχο ταυτότητας για να δείτε τις ενεργές συνεδρίες σας",
|
||||
"searchHint": "Αναζήτηση...",
|
||||
@@ -458,6 +458,10 @@
|
||||
"setNewPassword": "Ορίστε νέο κωδικό πρόσβασης",
|
||||
"deviceLock": "Κλείδωμα συσκευής",
|
||||
"hideContent": "Απόκρυψη περιεχομένου",
|
||||
"hideContentDescriptionAndroid": "Απόκρυψη περιεχομένου εφαρμογής στην εναλλαγή εφαρμογών και απενεργοποίηση στιγμιότυπων οθόνης",
|
||||
"hideContentDescriptioniOS": "Απόκρυψη περιεχομένου εφαρμογών στην εναλλαγή εφαρμογών",
|
||||
"autoLockFeatureDescription": "Χρόνος μετά τον οποίο η εφαρμογή κλειδώνει μετά την τοποθέτηση στο παρασκήνιο",
|
||||
"appLockDescription": "Επιλέξτε ανάμεσα στην προεπιλεγμένη οθόνη κλειδώματος της συσκευής σας και σε μια προσαρμοσμένη οθόνη κλειδώματος με ένα PIN ή έναν κωδικό πρόσβασης.",
|
||||
"pinLock": "Κλείδωμα καρφιτσωμάτων",
|
||||
"enterPin": "Εισαγωγή PIN",
|
||||
"setNewPin": "Ορίστε νέο PIN",
|
||||
|
||||
@@ -19,6 +19,20 @@
|
||||
"pleaseVerifyDetails": "Please verify the details and try again",
|
||||
"codeIssuerHint": "Issuer",
|
||||
"codeSecretKeyHint": "Secret Key",
|
||||
"secret": "Secret",
|
||||
"all": "All",
|
||||
"notes": "Notes",
|
||||
"notesLengthLimit": "Notes can be at most {count} characters long",
|
||||
"@notesLengthLimit": {
|
||||
"description": "Text to indicate the maximum number of characters allowed for notes",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"description": "The maximum number of characters allowed for notes",
|
||||
"type": "int",
|
||||
"example": "100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codeAccountHint": "Account (you@domain.com)",
|
||||
"codeTagHint": "Tag",
|
||||
"accountKeyType": "Type of key",
|
||||
@@ -34,6 +48,9 @@
|
||||
"nextTotpTitle": "next",
|
||||
"deleteCodeTitle": "Delete code?",
|
||||
"deleteCodeMessage": "Are you sure you want to delete this code? This action is irreversible.",
|
||||
"trashCode": "Trash code?",
|
||||
"trashCodeMessage": "Are you sure you want to trash code for {account}?",
|
||||
"trash": "Trash",
|
||||
"viewLogsAction": "View logs",
|
||||
"sendLogsDescription": "This will send across logs to help us debug your issue. While we take precautions to ensure that sensitive information is not logged, we encourage you to view these logs before sharing them.",
|
||||
"preparingLogsTitle": "Preparing logs...",
|
||||
@@ -100,6 +117,7 @@
|
||||
"emailVerificationToggle": "Email verification",
|
||||
"emailVerificationEnableWarning": "To avoid getting locked out of your account, be sure to store a copy of your email 2FA outside of Ente Auth before enabling email verification.",
|
||||
"authToChangeEmailVerificationSetting": "Please authenticate to change email verification",
|
||||
"authenticateGeneric": "Please authenticate",
|
||||
"authToViewYourRecoveryKey": "Please authenticate to view your recovery key",
|
||||
"authToChangeYourEmail": "Please authenticate to change your email",
|
||||
"authToChangeYourPassword": "Please authenticate to change your password",
|
||||
@@ -137,7 +155,8 @@
|
||||
"leaveFamily": "Leave family",
|
||||
"leaveFamilyMessage": "Are you sure that you want to leave the family plan?",
|
||||
"inFamilyPlanMessage": "You are on a family plan!",
|
||||
"swipeHint": "Swipe left to edit or remove codes",
|
||||
"hintForMobile": "Long press on a code to edit or remove.",
|
||||
"hintForDesktop": "Right click on a code to edit or remove.",
|
||||
"scan": "Scan",
|
||||
"scanACode": "Scan a code",
|
||||
"verify": "Verify",
|
||||
@@ -193,6 +212,10 @@
|
||||
"scanAQrCode": "Scan a QR code",
|
||||
"enterDetailsManually": "Enter details manually",
|
||||
"edit": "Edit",
|
||||
"share": "Share",
|
||||
"shareCodes": "Share codes",
|
||||
"shareCodesDuration": "Select the duration for which you want to share codes.",
|
||||
"restore": "Restore",
|
||||
"copiedToClipboard": "Copied to clipboard",
|
||||
"copiedNextToClipboard": "Copied next code to clipboard",
|
||||
"error": "Error",
|
||||
@@ -346,6 +369,7 @@
|
||||
"sigInBackupReminder": "Please export your codes to ensure that you have a backup you can restore from.",
|
||||
"offlineModeWarning": "You have chosen to proceed without backups. Please take manual backups to make sure your codes are safe.",
|
||||
"showLargeIcons": "Show large icons",
|
||||
"compactMode": "Compact mode",
|
||||
"shouldHideCode": "Hide codes",
|
||||
"doubleTapToViewHiddenCode": "You can double tap on an entry to view code",
|
||||
"focusOnSearchBar": "Focus search on app start",
|
||||
@@ -466,5 +490,7 @@
|
||||
"pinLock": "Pin lock",
|
||||
"enterPin": "Enter PIN",
|
||||
"setNewPin": "Set new PIN",
|
||||
"importFailureDescNew": "Could not parse the selected file."
|
||||
"importFailureDescNew": "Could not parse the selected file.",
|
||||
"appLockNotEnabled": "App lock not enabled",
|
||||
"appLockNotEnabledDescription": "Please enable app lock from Security > App Lock"
|
||||
}
|
||||
@@ -137,7 +137,6 @@
|
||||
"leaveFamily": "Dejar plan familiar",
|
||||
"leaveFamilyMessage": "¿Está seguro de que desea abandonar el plan familiar?",
|
||||
"inFamilyPlanMessage": "¡Estás en un plan familiar!",
|
||||
"swipeHint": "Deslice a la izquierda para editar o eliminar códigos",
|
||||
"scan": "Escanear",
|
||||
"scanACode": "Escanear un código",
|
||||
"verify": "Verificar",
|
||||
|
||||
@@ -92,7 +92,6 @@
|
||||
"leaveFamily": "خروج از طرح خانواده",
|
||||
"leaveFamilyMessage": "آیا مطمئنید که میخواهید از طرح خانواده خارج شوید؟",
|
||||
"inFamilyPlanMessage": "طرح خانواده برای شما فعال است!",
|
||||
"swipeHint": "برای ویرایش یا حذف کدها به چپ بکشید",
|
||||
"scan": "اسکن",
|
||||
"scanACode": "یک کد را اسکن کنید",
|
||||
"verify": "تایید",
|
||||
|
||||
@@ -106,7 +106,6 @@
|
||||
"leaveFamily": "Poistu perheestä",
|
||||
"leaveFamilyMessage": "Oletko varma että haluat jättää tämän perhemallin?",
|
||||
"inFamilyPlanMessage": "Olet perhemallissa!",
|
||||
"swipeHint": "Pyyhkäise vasemmalle muokataksesi tai poistaaksesi koodeja",
|
||||
"scan": "Lue",
|
||||
"scanACode": "Lue koodi",
|
||||
"verify": "Vahvista",
|
||||
|
||||
@@ -19,7 +19,20 @@
|
||||
"pleaseVerifyDetails": "Veuillez vérifier vos informations et réessayez",
|
||||
"codeIssuerHint": "Émetteur",
|
||||
"codeSecretKeyHint": "Clé secrète",
|
||||
"codeAccountHint": "Compte (vous@exemple.com)",
|
||||
"secret": "Confidentiel",
|
||||
"notes": "Notes",
|
||||
"notesLengthLimit": "Les notes peuvent contenir au maximum {count} caractères",
|
||||
"@notesLengthLimit": {
|
||||
"description": "Text to indicate the maximum number of characters allowed for notes",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"description": "The maximum number of characters allowed for notes",
|
||||
"type": "int",
|
||||
"example": "100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codeAccountHint": "Compte (nom@exemple.com)",
|
||||
"codeTagHint": "Tag",
|
||||
"accountKeyType": "Type de clé",
|
||||
"sessionExpired": "Session expirée",
|
||||
@@ -34,6 +47,9 @@
|
||||
"nextTotpTitle": "suivant",
|
||||
"deleteCodeTitle": "Supprimer le code ?",
|
||||
"deleteCodeMessage": "Êtes-vous sûr de vouloir supprimer ce code ? Cette action est irréversible.",
|
||||
"trashCode": "Supprimer le code?",
|
||||
"trashCodeMessage": "Êtes-vous sûr de vouloir supprimer le code pour {account}?",
|
||||
"trash": "Corbeille",
|
||||
"viewLogsAction": "Afficher les journaux",
|
||||
"sendLogsDescription": "Cela enverra des logs pour nous aider à déboguer votre problème. Bien que nous prenions des précautions pour nous assurer que les informations sensibles ne sont pas enregistrées, nous vous encourageons à consulter ces journaux avant de les partager.",
|
||||
"preparingLogsTitle": "Préparation des journaux...",
|
||||
@@ -100,6 +116,7 @@
|
||||
"emailVerificationToggle": "Vérification de l'adresse e-mail",
|
||||
"emailVerificationEnableWarning": "Si vous stockez le 2FA dans votre e-mail avec nous, l'activation de la vérification d'e-mail pourrait entraîner un blocage. Si vous êtes exclu d'un service, il se peut que vous ne puissiez pas vous connecter à l'autre.",
|
||||
"authToChangeEmailVerificationSetting": "Veuillez vous authentifier pour modifier votre adresse e-mail",
|
||||
"authenticateGeneric": "Veuillez vous authentifier",
|
||||
"authToViewYourRecoveryKey": "Veuillez vous authentifier pour afficher votre clé de récupération",
|
||||
"authToChangeYourEmail": "Veuillez vous authentifier pour modifier votre adresse e-mail",
|
||||
"authToChangeYourPassword": "Veuillez vous authentifier pour modifier votre mot de passe",
|
||||
@@ -118,7 +135,7 @@
|
||||
"existingUser": "Utilisateur existant",
|
||||
"newUser": "Nouveau dans Ente",
|
||||
"delete": "Supprimer",
|
||||
"enterYourPasswordHint": "Saisir votre mot de passe",
|
||||
"enterYourPasswordHint": "Entrez votre mot de passe",
|
||||
"forgotPassword": "Mot de passe oublié",
|
||||
"oops": "Oups",
|
||||
"suggestFeatures": "Suggérer des fonctionnalités",
|
||||
@@ -135,14 +152,15 @@
|
||||
"faq_a_5": "Vous pouvez activer le verrouillage FaceID dans Paramètres → Sécurité → Écran de verrouillage.",
|
||||
"somethingWentWrongMessage": "Quelque chose s'est mal passé, veuillez recommencer",
|
||||
"leaveFamily": "Quitter le plan familial",
|
||||
"leaveFamilyMessage": "Êtes-vous certains de vouloir quitter le plan familial?",
|
||||
"leaveFamilyMessage": "Êtes-vous sûr de vouloir quitter le plan familial ?",
|
||||
"inFamilyPlanMessage": "Vous êtes sur un plan familial !",
|
||||
"swipeHint": "Glisser vers la gauche pour modifier ou supprimer des codes",
|
||||
"hintForMobile": "Appuyez longuement sur un code pour modifier ou supprimer.",
|
||||
"hintForDesktop": "Clic droit sur un code à modifier ou à supprimer.",
|
||||
"scan": "Analyser",
|
||||
"scanACode": "Scanner un code",
|
||||
"verify": "Vérifier",
|
||||
"verifyEmail": "Vérifier l'e-mail",
|
||||
"enterCodeHint": "Saisir le code à 6 caractères de votre appli d'authentification",
|
||||
"enterCodeHint": "Entrez le code à 6 chiffres de votre application d'authentification",
|
||||
"lostDeviceTitle": "Appareil perdu ?",
|
||||
"twoFactorAuthTitle": "Authentification à deux facteurs",
|
||||
"passkeyAuthTitle": "Vérification du code d'accès",
|
||||
@@ -193,6 +211,10 @@
|
||||
"scanAQrCode": "Scanner un QR Code",
|
||||
"enterDetailsManually": "Saisir les détails manuellement",
|
||||
"edit": "Éditer",
|
||||
"share": "Partager",
|
||||
"shareCodes": "Partager les codes",
|
||||
"shareCodesDuration": "Sélectionnez la durée pour laquelle vous souhaitez partager les codes.",
|
||||
"restore": "Restaurer",
|
||||
"copiedToClipboard": "Copié dans le presse-papiers",
|
||||
"copiedNextToClipboard": "Code suivant copié dans le presse-papiers",
|
||||
"error": "Erreur",
|
||||
@@ -346,6 +368,7 @@
|
||||
"sigInBackupReminder": "Veuillez exporter vos codes pour vous assurer que vous avez une sauvegarde à partir de laquelle vous pouvez restaurer.",
|
||||
"offlineModeWarning": "Vous avez choisi de procéder sans sauvegarde. Veuillez prendre des sauvegardes manuelles pour vous assurer que vos codes sont sûrs.",
|
||||
"showLargeIcons": "Afficher les grandes icônes",
|
||||
"compactMode": "Mode compact",
|
||||
"shouldHideCode": "Cacher les codes",
|
||||
"doubleTapToViewHiddenCode": "Vous pouvez appuyer deux fois sur une entrée pour afficher le code",
|
||||
"focusOnSearchBar": "Cibler le champ de recherche au démarrage de l'application",
|
||||
@@ -446,7 +469,9 @@
|
||||
"viewRawCodes": "Afficher les codes bruts",
|
||||
"rawCodes": "Codes bruts",
|
||||
"rawCodeData": "Données de code brut",
|
||||
"appLock": "Verrouillage d'application",
|
||||
"noSystemLockFound": "Aucun verrou système trouvé",
|
||||
"toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Pour activer le verrouillage d'application, veuillez configurer un code d'accès ou le verrouillage de l'écran dans les paramètres de votre appareil.",
|
||||
"autoLock": "Verrouillage automatique",
|
||||
"immediately": "Immédiatement",
|
||||
"reEnterPassword": "Ressaisir le mot de passe",
|
||||
@@ -457,6 +482,9 @@
|
||||
"setNewPassword": "Définir un nouveau mot de passe",
|
||||
"deviceLock": "Verrouillage de l'appareil",
|
||||
"hideContent": "Masquer le contenu",
|
||||
"autoLockFeatureDescription": "Délai après lequel l'application se verrouille une fois qu'elle a été mise en arrière-plan",
|
||||
"appLockDescription": "Choisissez entre l'écran de verrouillage par défaut de votre appareil et un écran de verrouillage par code PIN ou mot de passe personnalisé.",
|
||||
"pinLock": "Verrouillage par code PIN",
|
||||
"enterPin": "Saisir le code PIN",
|
||||
"setNewPin": "Définir un nouveau code PIN",
|
||||
"importFailureDescNew": "Impossible de lire le fichier sélectionné."
|
||||
|
||||
@@ -126,7 +126,6 @@
|
||||
"leaveFamily": "עזוב משפחה",
|
||||
"leaveFamilyMessage": "האם אתה בטוח שאתה רוצה לעזוב את התוכנית המשפחתית?",
|
||||
"inFamilyPlanMessage": "אתה על תוכנית משפחתית!",
|
||||
"swipeHint": "החלק שמאלה כדי לערוך או להסיר קודים",
|
||||
"scan": "סרוק",
|
||||
"scanACode": "סרוק קוד",
|
||||
"verify": "אמת",
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
"account": "Akun",
|
||||
"unlock": "Buka",
|
||||
"recoveryKey": "Kunci pemulihan",
|
||||
"counterAppBarTitle": "Penghitung",
|
||||
"@counterAppBarTitle": {
|
||||
"description": "Text shown in the AppBar of the Counter Page"
|
||||
},
|
||||
"onBoardingBody": "Cadangkan kode 2FA kamu dengan aman",
|
||||
"onBoardingGetStarted": "Mulai",
|
||||
"setupFirstAccount": "Siapkan akun pertama kamu",
|
||||
@@ -9,12 +13,29 @@
|
||||
"qrCode": "Kode QR",
|
||||
"importEnterSetupKey": "Masukkan kunci penyiapan",
|
||||
"importAccountPageTitle": "Masukkan detail akun",
|
||||
"secretCanNotBeEmpty": "Rahasia tidak boleh kosong",
|
||||
"bothIssuerAndAccountCanNotBeEmpty": "Nama penerbit dan akun tidak boleh kosong",
|
||||
"incorrectDetails": "Rincian salah",
|
||||
"pleaseVerifyDetails": "Periksa kembali data kamu dan coba lagi",
|
||||
"codeIssuerHint": "Penerbit",
|
||||
"codeSecretKeyHint": "Kunci Rahasia",
|
||||
"secret": "Rahasia",
|
||||
"all": "Semua",
|
||||
"notes": "Catatan",
|
||||
"notesLengthLimit": "Catatan diperbolehkan sebanyak maksimal {count} karakter",
|
||||
"@notesLengthLimit": {
|
||||
"description": "Text to indicate the maximum number of characters allowed for notes",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"description": "The maximum number of characters allowed for notes",
|
||||
"type": "int",
|
||||
"example": "100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codeAccountHint": "Akun (kamu@domain.com)",
|
||||
"codeTagHint": "Tag",
|
||||
"accountKeyType": "Tipe kunci",
|
||||
"sessionExpired": "Sesi berakhir",
|
||||
"@sessionExpired": {
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
@@ -26,16 +47,38 @@
|
||||
"nextTotpTitle": "berikutnya",
|
||||
"deleteCodeTitle": "Hapus kode?",
|
||||
"deleteCodeMessage": "Apakah kamu yakin ingin menghapus kode ini? Tindakan ini tidak dapat dikembalikan ke semula.",
|
||||
"trashCode": "Hapus kode?",
|
||||
"trashCodeMessage": "Apakah anda yakin ingin menghapus kode untuk {account}?",
|
||||
"trash": "Hapus",
|
||||
"viewLogsAction": "Lihat log",
|
||||
"sendLogsDescription": "Langkah ini akan mengirimkan log untuk membantu kami menganalisa masalah kamu. Meskipun kami melakukan tindakan pencegahan untuk memastikan bahwa informasi sensitif tidak dicatat, kami menganjurkan kamu untuk melihat log ini sebelum membagikannya.",
|
||||
"preparingLogsTitle": "Menyiapkan log...",
|
||||
"emailLogsTitle": "Log email",
|
||||
"emailLogsMessage": "Harap kirim log ke {email}",
|
||||
"@emailLogsMessage": {
|
||||
"placeholders": {
|
||||
"email": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"copyEmailAction": "Salin email",
|
||||
"exportLogsAction": "Ekspor log",
|
||||
"reportABug": "Laporkan bug",
|
||||
"crashAndErrorReporting": "Pelaporan Error dan Crash",
|
||||
"reportBug": "Laporkan bug",
|
||||
"emailUsMessage": "Harap email kami di {email}",
|
||||
"@emailUsMessage": {
|
||||
"placeholders": {
|
||||
"email": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"contactSupport": "Hubungi dukungan",
|
||||
"rateUsOnStore": "Nilai kami di {storeName}",
|
||||
"blog": "Blog",
|
||||
"merchandise": "Merchandise",
|
||||
"verifyPassword": "Verifikasi sandi",
|
||||
"pleaseWait": "Harap tunggu...",
|
||||
"generatingEncryptionKeysTitle": "Membuat kunci enkripsi...",
|
||||
@@ -52,11 +95,16 @@
|
||||
"data": "Data",
|
||||
"importCodes": "Impor kode",
|
||||
"importTypePlainText": "Teks biasa",
|
||||
"importTypeEnteEncrypted": "Eksport enkripsi ente",
|
||||
"passwordForDecryptingExport": "Kata sandi untuk mendekripsi ekspor",
|
||||
"passwordEmptyError": "Kata sandi tidak boleh kosong",
|
||||
"importFromApp": "Impor kode dari {appName}",
|
||||
"importSelectJsonFile": "Pilih File JSON",
|
||||
"importSelectAppExport": "Pilih file ekspor dari {appName}",
|
||||
"importEnteEncGuide": "Pilih file enkripsi JSON yang telah diekspor dari Ente",
|
||||
"importRaivoGuide": "Gunakan opsi \"Export OTPs to Zip archive\" pada pengaturan Raivo.\n\nEkstrak file zip dan impor file JSON tersebut.",
|
||||
"importBitwardenGuide": "Gunakan opsi \"Export vault\" didalam fitur Bitwarden Tools dan impor file JSON yang tidak terenkripsi.",
|
||||
"importAegisGuide": "Gunakan opsi \"Export vault\" didalam fitur Bitwarden Tools dan impor file JSON yang tidak terenkripsi.",
|
||||
"selectFile": "Pilih file",
|
||||
"emailVerificationToggle": "Verifikasi email",
|
||||
"emailVerificationEnableWarning": "Untuk menghindari akun kamu terkunci, pastikan untuk menyimpan salinan 2FA email kamu di luar Ente Auth sebelum mengaktifkan verifikasi email.",
|
||||
|
||||
@@ -137,7 +137,6 @@
|
||||
"leaveFamily": "Abbandona il piano famiglia",
|
||||
"leaveFamilyMessage": "Sei sicuro di voler uscire dal piano famiglia?",
|
||||
"inFamilyPlanMessage": "Sei un utente con piano famiglia!",
|
||||
"swipeHint": "Scorri a sinistra per modificare o rimuovere i codici",
|
||||
"scan": "Scansiona",
|
||||
"scanACode": "Scansiona un codice",
|
||||
"verify": "Verifica",
|
||||
@@ -466,5 +465,7 @@
|
||||
"pinLock": "Blocco con PIN",
|
||||
"enterPin": "Inserisci PIN",
|
||||
"setNewPin": "Imposta un nuovo PIN",
|
||||
"importFailureDescNew": "Impossibile elaborare il file selezionato."
|
||||
"importFailureDescNew": "Impossibile elaborare il file selezionato.",
|
||||
"appLockNotEnabled": "Blocco app non abilitato",
|
||||
"appLockNotEnabledDescription": "Si prega di abilitare il blocco dell'app da Sicurezza > Blocco App"
|
||||
}
|
||||
@@ -137,7 +137,6 @@
|
||||
"leaveFamily": "ファミリープランから退会",
|
||||
"leaveFamilyMessage": "本当にファミリープランを退会しますか?",
|
||||
"inFamilyPlanMessage": "ファミリープランに入会しています!",
|
||||
"swipeHint": "左にスワイプしてコードを編集、削除します",
|
||||
"scan": "読み取り",
|
||||
"scanACode": "コードを読み取り",
|
||||
"verify": "認証",
|
||||
|
||||
@@ -137,7 +137,6 @@
|
||||
"leaveFamily": "Familie verlaten",
|
||||
"leaveFamilyMessage": "Weet je zeker dat je het familie-plan wil verlaten?",
|
||||
"inFamilyPlanMessage": "Je hebt een familie-plan!",
|
||||
"swipeHint": "Veeg naar links om codes te bewerken of te verwijderen",
|
||||
"scan": "Scannen",
|
||||
"scanACode": "Scan een code",
|
||||
"verify": "Verifiëren",
|
||||
|
||||
@@ -19,6 +19,20 @@
|
||||
"pleaseVerifyDetails": "Prosimy zweryfikować szczegóły i spróbować ponownie",
|
||||
"codeIssuerHint": "Wydawca",
|
||||
"codeSecretKeyHint": "Tajny Klucz",
|
||||
"secret": "Sekret",
|
||||
"all": "Wszystko",
|
||||
"notes": "Notatki",
|
||||
"notesLengthLimit": "Notatki mogą mieć maksymalnie {count} znaków",
|
||||
"@notesLengthLimit": {
|
||||
"description": "Text to indicate the maximum number of characters allowed for notes",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"description": "The maximum number of characters allowed for notes",
|
||||
"type": "int",
|
||||
"example": "100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codeAccountHint": "Konto (ty@domena.com)",
|
||||
"codeTagHint": "Oznacz",
|
||||
"accountKeyType": "Rodzaj klucza",
|
||||
@@ -34,6 +48,9 @@
|
||||
"nextTotpTitle": "dalej",
|
||||
"deleteCodeTitle": "Usunąć kod?",
|
||||
"deleteCodeMessage": "Czy na pewno chcesz usunąć ten kod? Ta akcja jest nieodwracalna.",
|
||||
"trashCode": "Przenieść kod do kosza?",
|
||||
"trashCodeMessage": "Czy na pewno chcesz przenieść do kosza kod dla {account}?",
|
||||
"trash": "Kosz",
|
||||
"viewLogsAction": "Wyświetl logi",
|
||||
"sendLogsDescription": "Spowoduje to przesłanie logów, które pomogą nam rozwiązać Twój problem. Chociaż podejmujemy środki ostrożności, aby zapewnić, że wrażliwe informacje nie są rejestrowane, zachęcamy do obejrzenia tych dzienników przed ich udostępnieniem.",
|
||||
"preparingLogsTitle": "Przygotowywanie logów...",
|
||||
@@ -100,6 +117,7 @@
|
||||
"emailVerificationToggle": "Weryfikacja e-mail",
|
||||
"emailVerificationEnableWarning": "Aby uniknąć zablokowania się z konta, upewnij się, że przed włączeniem weryfikacji e-mail przechowujesz kopię 2FA dla swojego adresu e-mail poza Ente Auth.",
|
||||
"authToChangeEmailVerificationSetting": "Prosimy uwierzytelnić się, aby zmienić weryfikację e-mail",
|
||||
"authenticateGeneric": "Prosimy się uwierzytelnić",
|
||||
"authToViewYourRecoveryKey": "Prosimy uwierzytelnić się, aby wyświetlić swój klucz odzyskiwania",
|
||||
"authToChangeYourEmail": "Prosimy uwierzytelnić się, aby zmienić swój adres e-mail",
|
||||
"authToChangeYourPassword": "Prosimy uwierzytelnić się, aby zmienić hasło",
|
||||
@@ -137,7 +155,8 @@
|
||||
"leaveFamily": "Opuść rodzinę",
|
||||
"leaveFamilyMessage": "Czy jesteś pewien/pewna, że chcesz opuścić plan rodzinny?",
|
||||
"inFamilyPlanMessage": "Jesteś w planie rodzinnym!",
|
||||
"swipeHint": "Przesuń palcem w lewo, aby edytować lub usunąć kody",
|
||||
"hintForMobile": "Przytrzymaj kod, aby edytować lub usunąć.",
|
||||
"hintForDesktop": "Kliknij prawym przyciskiem myszy na kod, aby edytować lub usunąć.",
|
||||
"scan": "Skanuj",
|
||||
"scanACode": "Skanuj kod",
|
||||
"verify": "Zweryfikuj",
|
||||
@@ -193,6 +212,10 @@
|
||||
"scanAQrCode": "Zeskanuj kod QR",
|
||||
"enterDetailsManually": "Wprowadź dane ręcznie",
|
||||
"edit": "Edytuj",
|
||||
"share": "Udostępnij",
|
||||
"shareCodes": "Udostępnij kody",
|
||||
"shareCodesDuration": "Wybierz okres, przez który chcesz udostępniać kody.",
|
||||
"restore": "Przywróć",
|
||||
"copiedToClipboard": "Skopiowano do schowka",
|
||||
"copiedNextToClipboard": "Skopiowano następny kod do schowka",
|
||||
"error": "Błąd",
|
||||
@@ -346,6 +369,7 @@
|
||||
"sigInBackupReminder": "Prosimy wyeksportować swoje kody, aby upewnić się, że masz kopię zapasową, z której możesz przywrócić swoje kody.",
|
||||
"offlineModeWarning": "Zdecydowano się kontynuować bez kopii zapasowych. Prosimy wykonywać ręczne kopie zapasowe, aby upewnić się, że Twoje kody są bezpieczne.",
|
||||
"showLargeIcons": "Pokaż duże ikony",
|
||||
"compactMode": "Tryb kompaktowy",
|
||||
"shouldHideCode": "Ukryj kody",
|
||||
"doubleTapToViewHiddenCode": "Możesz kliknąć dwukrotnie na wpis, aby wyświetlić kod",
|
||||
"focusOnSearchBar": "Uaktywnij wyszukiwanie przy uruchamianiu aplikacji",
|
||||
@@ -466,5 +490,7 @@
|
||||
"pinLock": "Blokada PIN",
|
||||
"enterPin": "Wprowadź kod PIN",
|
||||
"setNewPin": "Ustaw nowy kod PIN",
|
||||
"importFailureDescNew": "Nie udało się przetworzyć wybranego pliku."
|
||||
"importFailureDescNew": "Nie udało się przetworzyć wybranego pliku.",
|
||||
"appLockNotEnabled": "Blokada aplikacji nie jest włączona",
|
||||
"appLockNotEnabledDescription": "Prosimy włączyć blokadę aplikacji z Zabezpieczenia > Blokada Aplikacji"
|
||||
}
|
||||
@@ -19,6 +19,20 @@
|
||||
"pleaseVerifyDetails": "Por favor, verifique os detalhes e tente novamente",
|
||||
"codeIssuerHint": "Emissor",
|
||||
"codeSecretKeyHint": "Chave secreta",
|
||||
"secret": "Secreto",
|
||||
"all": "Todos",
|
||||
"notes": "Notas",
|
||||
"notesLengthLimit": "Notas tem um limite de até {count} caracteres",
|
||||
"@notesLengthLimit": {
|
||||
"description": "Text to indicate the maximum number of characters allowed for notes",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"description": "The maximum number of characters allowed for notes",
|
||||
"type": "int",
|
||||
"example": "100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codeAccountHint": "Conta (você@domínio.com)",
|
||||
"codeTagHint": "Etiqueta",
|
||||
"accountKeyType": "Tipo de chave",
|
||||
@@ -34,6 +48,9 @@
|
||||
"nextTotpTitle": "avançar",
|
||||
"deleteCodeTitle": "Apagar código?",
|
||||
"deleteCodeMessage": "Deseja mesmo excluir este código? Esta ação é irreversível.",
|
||||
"trashCode": "Excluir código?",
|
||||
"trashCodeMessage": "Você tem certeza de que quer excluir o código para {account}?",
|
||||
"trash": "Excluir",
|
||||
"viewLogsAction": "Ver logs",
|
||||
"sendLogsDescription": "Isto compartilhará seus dados para nos ajudarmos a resolver seu problema. Enquanto tomamos precauções para ter certeza que as informações sensíveis não estejam registradas, nós encorajamos você a visualizar esses dados antes de compartilhá-los.",
|
||||
"preparingLogsTitle": "Preparando logs...",
|
||||
@@ -100,6 +117,7 @@
|
||||
"emailVerificationToggle": "Verificação por e-mail",
|
||||
"emailVerificationEnableWarning": "Para evitar ficar bloqueado do acesso a sua conta, certifique-se de armazenar uma cópia do código 2FA do seu e-mail fora do Ente Auth antes de habilitar a verificação por e-mail.",
|
||||
"authToChangeEmailVerificationSetting": "Por favor, autentique-se para alterar a verificação por e-mail",
|
||||
"authenticateGeneric": "Por favor, autentique",
|
||||
"authToViewYourRecoveryKey": "Por favor, autentique-se para visualizar sua chave de recuperação",
|
||||
"authToChangeYourEmail": "Por favor, autentique-se para alterar o seu e-mail",
|
||||
"authToChangeYourPassword": "Por favor, autentique-se para alterar sua senha",
|
||||
@@ -137,7 +155,8 @@
|
||||
"leaveFamily": "Sair da família",
|
||||
"leaveFamilyMessage": "Deseja mesmo sair do plano familiar?",
|
||||
"inFamilyPlanMessage": "Você está em um plano familiar!",
|
||||
"swipeHint": "Deslize para a esquerda para editar ou remover os códigos",
|
||||
"hintForMobile": "Pressione em um código para editar ou excluir.",
|
||||
"hintForDesktop": "Clique esquerdo em um código para editar ou excluir.",
|
||||
"scan": "Escanear",
|
||||
"scanACode": "Escanear código",
|
||||
"verify": "Verificar",
|
||||
@@ -193,6 +212,10 @@
|
||||
"scanAQrCode": "Escanear QR code",
|
||||
"enterDetailsManually": "Inserir dados manualmente",
|
||||
"edit": "Editar",
|
||||
"share": "Compartilhar",
|
||||
"shareCodes": "Compartilhar códigos",
|
||||
"shareCodesDuration": "Selecione a duração em que você queira compartilhar os códigos.",
|
||||
"restore": "Restaurar",
|
||||
"copiedToClipboard": "Copiado para a área de transferência",
|
||||
"copiedNextToClipboard": "Próximo código copiado para a área de transferência",
|
||||
"error": "Erro",
|
||||
@@ -346,6 +369,7 @@
|
||||
"sigInBackupReminder": "Por favor, exporte seus códigos para garantir que você tenha um backup do qual você possa restaurar.",
|
||||
"offlineModeWarning": "Você escolheu prosseguir sem backups. Por favor, faça backups manuais para ter certeza de que seus códigos estão seguros.",
|
||||
"showLargeIcons": "Mostrar ícones grandes",
|
||||
"compactMode": "Modo compacto",
|
||||
"shouldHideCode": "Ocultar códigos",
|
||||
"doubleTapToViewHiddenCode": "Você pode tocar duas vezes em uma entrada para ver o código",
|
||||
"focusOnSearchBar": "Foco na busca ao iniciar o app",
|
||||
@@ -466,5 +490,7 @@
|
||||
"pinLock": "Bloqueio PIN",
|
||||
"enterPin": "Insira o PIN",
|
||||
"setNewPin": "Definir novo PIN",
|
||||
"importFailureDescNew": "Não foi possível analisar o arquivo selecionado."
|
||||
"importFailureDescNew": "Não foi possível analisar o arquivo selecionado.",
|
||||
"appLockNotEnabled": "Bloqueio de aplicativo não ativado",
|
||||
"appLockNotEnabledDescription": "Ative o bloqueio de aplicativo em Segurança > Bloqueio de aplicativo"
|
||||
}
|
||||
@@ -137,7 +137,6 @@
|
||||
"leaveFamily": "Покинуть семью",
|
||||
"leaveFamilyMessage": "Вы уверены, что хотите отказаться от семейного плана?",
|
||||
"inFamilyPlanMessage": "Вы на семейном плане!",
|
||||
"swipeHint": "Проведите пальцем влево, чтобы отредактировать или удалить коды",
|
||||
"scan": "Сканировать",
|
||||
"scanACode": "Сканировать QR-код",
|
||||
"verify": "Подтвердить",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"account": "Konto",
|
||||
"account": "Účet",
|
||||
"unlock": "Odomknúť",
|
||||
"recoveryKey": "Kľúč pre obnovenie",
|
||||
"counterAppBarTitle": "Počítadlo",
|
||||
@@ -8,18 +8,18 @@
|
||||
},
|
||||
"onBoardingBody": "Zabezpečte svoje kódy 2FA",
|
||||
"onBoardingGetStarted": "Poďme na to",
|
||||
"setupFirstAccount": "Vytvorte svoj prvý účet",
|
||||
"setupFirstAccount": "Nastav si svoj prvý účet",
|
||||
"importScanQrCode": "Naskenovať QR kód",
|
||||
"qrCode": "QR kód",
|
||||
"importEnterSetupKey": "Vložte kľúč nastavenia",
|
||||
"importAccountPageTitle": "Vložte detaily o konte",
|
||||
"importAccountPageTitle": "Zadaj údaje o účte",
|
||||
"secretCanNotBeEmpty": "Tajný kľúč nemôže ostať prázdny",
|
||||
"bothIssuerAndAccountCanNotBeEmpty": "Buď vydavateľ alebo účet nemôže ostať prázdny",
|
||||
"bothIssuerAndAccountCanNotBeEmpty": "Vydavateľ aj účet nemôžu byť prázdne",
|
||||
"incorrectDetails": "Chybné údaje",
|
||||
"pleaseVerifyDetails": "Prosím, skontrolujte svoje údaje a skúste to znova",
|
||||
"codeIssuerHint": "Vydavateľ",
|
||||
"codeSecretKeyHint": "Tajný kľúč",
|
||||
"codeAccountHint": "Konto (ucet@domena.com)",
|
||||
"codeAccountHint": "Účet (ty@domena.sk)",
|
||||
"codeTagHint": "Tag",
|
||||
"accountKeyType": "Typ kľúča",
|
||||
"sessionExpired": "Relácia vypršala",
|
||||
@@ -137,7 +137,6 @@
|
||||
"leaveFamily": "Opustiť rodinku",
|
||||
"leaveFamilyMessage": "Ste si istý, že chcete opustiť rodinku?",
|
||||
"inFamilyPlanMessage": "Ste prihlásený k rodinke!",
|
||||
"swipeHint": "Potiahnite doľava pre upravenie alebo vymazanie kódov",
|
||||
"scan": "Skenovať",
|
||||
"scanACode": "Skenovať kód",
|
||||
"verify": "Overiť",
|
||||
@@ -147,7 +146,7 @@
|
||||
"twoFactorAuthTitle": "Dvojfaktorové overovanie",
|
||||
"passkeyAuthTitle": "Overenie pomocou passkey",
|
||||
"verifyPasskey": "Overiť passkey",
|
||||
"recoverAccount": "Obnoviť konto",
|
||||
"recoverAccount": "Obnoviť účet",
|
||||
"enterRecoveryKeyHint": "Vložte váš kód pre obnovenie",
|
||||
"recover": "Obnoviť",
|
||||
"contactSupportViaEmailMessage": "Pošlite e-mail na adresu {email} z vašej registrovanej e-mailovej adresy",
|
||||
@@ -163,13 +162,13 @@
|
||||
"enterEmailHint": "Zadajte vašu emailovú adresu",
|
||||
"invalidEmailTitle": "Neplatná emailová adresa",
|
||||
"invalidEmailMessage": "Zadajte platnú e-mailovú adresu.",
|
||||
"deleteAccount": "Odstrániť konto",
|
||||
"deleteAccountQuery": "Bude nám tu bez vás smutno. Vyskytol sa nejaký problém?",
|
||||
"deleteAccount": "Odstrániť účet",
|
||||
"deleteAccountQuery": "Bude nám ľúto ak odídeš. Máš nejaký problém?",
|
||||
"yesSendFeedbackAction": "Áno, odoslať spätnú väzbu",
|
||||
"noDeleteAccountAction": "Nie, odstrániť účet",
|
||||
"initiateAccountDeleteTitle": "Pre odstránenie účtu sa musíte overiť",
|
||||
"initiateAccountDeleteTitle": "Je potrebné overenie pre spustenie odstránenia účtu",
|
||||
"sendEmail": "Odoslať email",
|
||||
"createNewAccount": "Vytvoriť nové konto",
|
||||
"createNewAccount": "Vytvoriť nový účet",
|
||||
"weakStrength": "Slabé",
|
||||
"strongStrength": "Silné",
|
||||
"moderateStrength": "Mierne",
|
||||
@@ -353,8 +352,8 @@
|
||||
"editCodeAuthMessage": "Overte sa pre zmenu kódu",
|
||||
"deleteCodeAuthMessage": "Overte sa pre vymazanie kódu",
|
||||
"showQRAuthMessage": "Overte sa pre zobrazenie QR kódu",
|
||||
"confirmAccountDeleteTitle": "Potvrdiť odstránenie účtu",
|
||||
"confirmAccountDeleteMessage": "Tento účet je prepojený s inými aplikáciami Ente, ak nejaké používate.\n\nVšetky nahrané údaje v aplikáciách od Ente budú naplánované na výmaz a váš účet bude natrvalo odstránený.",
|
||||
"confirmAccountDeleteTitle": "Potvrď odstránenie účtu",
|
||||
"confirmAccountDeleteMessage": "Tento účet je prepojený s inými aplikáciami Ente, ak nejaké používaš.\n\nTvoje nahrané údaje vo všetkých Ente aplikáciách budú naplánované na odstránenie a tvoj účet bude natrvalo odstránený.",
|
||||
"androidBiometricHint": "Overiť identitu",
|
||||
"@androidBiometricHint": {
|
||||
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
|
||||
@@ -410,7 +409,7 @@
|
||||
"noInternetConnection": "Žiadne internetové pripojenie",
|
||||
"pleaseCheckYourInternetConnectionAndTryAgain": "Skontrolujte svoje internetové pripojenie a skúste to znova.",
|
||||
"signOutFromOtherDevices": "Odhlásiť sa z iných zariadení",
|
||||
"signOutOtherBody": "Ak si myslíte, že niekto môže vedieť vaše heslo, môžete vynútiť odhlásenie všetkých ostatných zariadení vo vašom účte.",
|
||||
"signOutOtherBody": "Ak si myslíš, že by niekto mohol poznať tvoje heslo, môžeš vynútiť odhlásenie všetkých ostatných zariadení používajúcich tvoj účet.",
|
||||
"signOutOtherDevices": "Odhlásiť iné zariadenie",
|
||||
"doNotSignOut": "Neodhlasovať",
|
||||
"hearUsWhereTitle": "Ako ste sa dozvedeli o Ente? (voliteľné)",
|
||||
|
||||
@@ -15,16 +15,20 @@
|
||||
"pleaseVerifyDetails": "Kontrollera dina detaljer och försök igen",
|
||||
"codeIssuerHint": "Utfärdare",
|
||||
"codeSecretKeyHint": "Secret Key",
|
||||
"all": "Alla",
|
||||
"codeAccountHint": "Konto (du@domän.com)",
|
||||
"codeTagHint": "Tagg",
|
||||
"sessionExpired": "Sessionen har gått ut",
|
||||
"@sessionExpired": {
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
},
|
||||
"pleaseLoginAgain": "Vänligen logga in igen",
|
||||
"pleaseLoginAgain": "Logga in igen",
|
||||
"loggingOut": "Loggar ut...",
|
||||
"saveAction": "Spara",
|
||||
"nextTotpTitle": "nästa",
|
||||
"deleteCodeTitle": "Radera kod?",
|
||||
"deleteCodeMessage": "Vill du ta bort den här koden? Det går inte att ångra den här åtgärden.",
|
||||
"trash": "Papperskorg",
|
||||
"viewLogsAction": "Visa loggar",
|
||||
"emailLogsTitle": "E-posta loggar",
|
||||
"emailLogsMessage": "Skicka loggarna till {email}",
|
||||
@@ -61,8 +65,15 @@
|
||||
"welcomeBack": "Välkommen tillbaka!",
|
||||
"changePassword": "Ändra lösenord",
|
||||
"importCodes": "Importera koder",
|
||||
"importFromApp": "Importera koder från {appName}",
|
||||
"importSelectJsonFile": "Välj JSON-fil",
|
||||
"exportCodes": "Exportera koder",
|
||||
"importLabel": "Importera",
|
||||
"selectFile": "Välj fil",
|
||||
"authToViewYourRecoveryKey": "Autentisera för att visa din återställningsnyckel",
|
||||
"authToChangeYourEmail": "Autentisera för att ändra din e-postadress",
|
||||
"authToChangeYourPassword": "Autentisera för att ändra ditt lösenord",
|
||||
"ok": "OK",
|
||||
"cancel": "Avbryt",
|
||||
"yes": "Ja",
|
||||
"no": "Nej",
|
||||
@@ -94,6 +105,10 @@
|
||||
"close": "Stäng",
|
||||
"selectLanguage": "Välj språk",
|
||||
"language": "Språk",
|
||||
"security": "Säkerhet",
|
||||
"lockscreen": "Låsskärm",
|
||||
"viewActiveSessions": "Visa aktiva sessioner",
|
||||
"authToViewYourActiveSessions": "Autentisera för att visa dina aktiva sessioner",
|
||||
"searchHint": "Sök...",
|
||||
"search": "Sök",
|
||||
"sorryUnableToGenCode": "Tyvärr, det gick inte att generera en kod för {issuerName}",
|
||||
@@ -102,6 +117,9 @@
|
||||
"scanAQrCode": "Skanna en QR-kod",
|
||||
"enterDetailsManually": "Ange uppgifter manuellt",
|
||||
"edit": "Redigera",
|
||||
"share": "Dela",
|
||||
"shareCodes": "Dela koder",
|
||||
"restore": "Återställ",
|
||||
"copiedToClipboard": "Kopierat till urklipp",
|
||||
"copiedNextToClipboard": "Kopierade nästa kod till urklipp",
|
||||
"error": "Fel",
|
||||
@@ -109,12 +127,26 @@
|
||||
"recoveryKeyOnForgotPassword": "Om du glömmer ditt lösenord är det enda sättet du kan återställa dina data med denna nyckel.",
|
||||
"saveKey": "Spara nyckel",
|
||||
"save": "Spara",
|
||||
"send": "Skicka",
|
||||
"back": "Tillbaka",
|
||||
"createAccount": "Skapa konto",
|
||||
"passwordStrength": "Lösenordsstyrka: {passwordStrengthValue}",
|
||||
"@passwordStrength": {
|
||||
"description": "Text to indicate the password strength",
|
||||
"placeholders": {
|
||||
"passwordStrengthValue": {
|
||||
"description": "The strength of the password as a string",
|
||||
"type": "String",
|
||||
"example": "Weak or Moderate or Strong"
|
||||
}
|
||||
},
|
||||
"message": "Password Strength: {passwordStrengthText}"
|
||||
},
|
||||
"password": "Lösenord",
|
||||
"privacyPolicyTitle": "Integritetspolicy",
|
||||
"termsOfServicesTitle": "Villkor",
|
||||
"encryption": "Kryptering",
|
||||
"setPasswordTitle": "Ställ in lösenord",
|
||||
"changePasswordTitle": "Ändra lösenord",
|
||||
"resetPasswordTitle": "Återställ lösenord",
|
||||
"encryptionKeys": "Krypteringsnycklar",
|
||||
@@ -151,8 +183,12 @@
|
||||
"incorrectRecoveryKey": "Felaktig återställningsnyckel",
|
||||
"enterPassword": "Ange lösenord",
|
||||
"export": "Exportera",
|
||||
"signInToBackup": "Logga in för att säkerhetskopiera dina koder",
|
||||
"singIn": "Logga in",
|
||||
"shouldHideCode": "Dölj koder",
|
||||
"editCodeAuthMessage": "Autentisera för att redigera kod",
|
||||
"deleteCodeAuthMessage": "Autentisera för att radera kod",
|
||||
"showQRAuthMessage": "Autentisera för att visa QR-kod",
|
||||
"androidCancelButton": "Avbryt",
|
||||
"@androidCancelButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
|
||||
@@ -163,16 +199,23 @@
|
||||
},
|
||||
"noInternetConnection": "Ingen internetanslutning",
|
||||
"pleaseCheckYourInternetConnectionAndTryAgain": "Kontrollera din internetanslutning och försök igen.",
|
||||
"signOutOtherDevices": "Logga ut andra enheter",
|
||||
"loginSessionExpiredDetails": "Din session har upphört. Logga in igen.",
|
||||
"tags": "Taggar",
|
||||
"createNewTag": "Skapa ny tagg",
|
||||
"tag": "Tagg",
|
||||
"create": "Skapa",
|
||||
"editTag": "Redigera tagg",
|
||||
"deleteTagTitle": "Radera tagg?",
|
||||
"immediately": "Omedelbart",
|
||||
"reEnterPassword": "Ange lösenord igen",
|
||||
"reEnterPin": "Ange PIN-kod igen",
|
||||
"next": "Nästa",
|
||||
"tooManyIncorrectAttempts": "För många felaktiga försök",
|
||||
"tapToUnlock": "Tryck för att låsa upp",
|
||||
"setNewPassword": "Ange nytt lösenord",
|
||||
"setNewPassword": "Ställ in nytt lösenord",
|
||||
"deviceLock": "Enhetslås",
|
||||
"hideContent": "Dölj innehåll",
|
||||
"enterPin": "Ange PIN-kod",
|
||||
"setNewPin": "Ange ny PIN-kod"
|
||||
"setNewPin": "Ställ in ny PIN-kod"
|
||||
}
|
||||
1
auth/lib/l10n/arb/app_ta.arb
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -132,7 +132,6 @@
|
||||
"leaveFamily": "Leave family",
|
||||
"leaveFamilyMessage": "Are you sure that you want to leave the family plan?",
|
||||
"inFamilyPlanMessage": "You are on a family plan!",
|
||||
"swipeHint": "Swipe left to edit or remove codes",
|
||||
"scan": "Scan",
|
||||
"scanACode": "Scan a code",
|
||||
"verify": "Verify",
|
||||
|
||||
@@ -137,7 +137,6 @@
|
||||
"leaveFamily": "Aile planından ayrıl",
|
||||
"leaveFamilyMessage": "Aile planından ayrılmak istediğinize emin misiniz?",
|
||||
"inFamilyPlanMessage": "Aile planı kullanıyorsunuz!",
|
||||
"swipeHint": "Kodları düzenlemek ya da kaldırmak için sola kaydırın",
|
||||
"scan": "Tara",
|
||||
"scanACode": "Bir kodu tarayın",
|
||||
"verify": "Doğrula",
|
||||
|
||||
@@ -137,7 +137,6 @@
|
||||
"leaveFamily": "Залишити сімейний план",
|
||||
"leaveFamilyMessage": "Ви впевнені, що хочете залишити сімейний план?",
|
||||
"inFamilyPlanMessage": "Ви знаходитесь на сімейному плані!",
|
||||
"swipeHint": "Проведіть пальцем вліво, щоб редагувати або видаляти коди",
|
||||
"scan": "Сканувати",
|
||||
"scanACode": "Сканувати код",
|
||||
"verify": "Перевірити",
|
||||
|
||||
@@ -21,12 +21,13 @@
|
||||
"codeSecretKeyHint": "Khóa bí mật",
|
||||
"codeAccountHint": "Tài khoản (bạn@miền.com)",
|
||||
"codeTagHint": "Thẻ",
|
||||
"accountKeyType": "Loại khóa",
|
||||
"sessionExpired": "Phiên làm việc đã hết hạn",
|
||||
"@sessionExpired": {
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
},
|
||||
"pleaseLoginAgain": "Vui lòng đăng nhập lại",
|
||||
"loggingOut": "Đang thoát...",
|
||||
"loggingOut": "Đang đăng xuất...",
|
||||
"timeBasedKeyType": "Dựa trên thời gian (TOTP)",
|
||||
"counterBasedKeyType": "Dựa trên bộ đếm (HOTP)",
|
||||
"saveAction": "Lưu",
|
||||
@@ -74,7 +75,7 @@
|
||||
"supportDevs": "Đăng ký <bold-green>ente</bold-green> để hỗ trợ dự án này.",
|
||||
"supportDiscount": "Sử dụng mã giảm giá \"AUTH\" để được giảm 10% trong năm đầu tiên",
|
||||
"changeEmail": "Thay đổi email",
|
||||
"changePassword": "Thay đổi mật khẩu",
|
||||
"changePassword": "Đổi mật khẩu",
|
||||
"data": "Dữ liệu",
|
||||
"importCodes": "Nhập mã",
|
||||
"importTypePlainText": "Văn bản thuần",
|
||||
@@ -131,17 +132,16 @@
|
||||
"faq_a_4": "Bạn có thể hỗ trợ sự phát triển của dự án này bằng cách đăng ký ứng dụng Ảnh @ ente.io của chúng tôi.",
|
||||
"faq_q_5": "Làm sao để tôi bật FaceID trong ente",
|
||||
"faq_a_5": "Bạn có thể bật khóa FaceID trong Cài đặt → Bảo mật → Màn hình khóa.",
|
||||
"somethingWentWrongMessage": "Phát hiện có lỗi, xin thử lại",
|
||||
"somethingWentWrongMessage": "Đã xảy ra lỗi, xin thử lại",
|
||||
"leaveFamily": "Rời khỏi gia đình",
|
||||
"leaveFamilyMessage": "Bạn có chắc chắn muốn thoát khỏi gói dành cho gia đình không?",
|
||||
"inFamilyPlanMessage": "Bạn đang sử dụng gói dành cho gia đình!",
|
||||
"swipeHint": "Vuốt sang trái để chỉnh sửa hoặc xóa mã",
|
||||
"scan": "Quét",
|
||||
"scanACode": "Quét mã",
|
||||
"verify": "Xác minh",
|
||||
"verifyEmail": "Xác nhận địa chỉ Email",
|
||||
"enterCodeHint": "Nhập mã gồm 6 chữ số từ ứng dụng xác thực của bạn",
|
||||
"lostDeviceTitle": "Bạn đã mất thiết bị?",
|
||||
"lostDeviceTitle": "Mất thiết bị?",
|
||||
"twoFactorAuthTitle": "Xác thực hai yếu tố",
|
||||
"recoverAccount": "Khôi phục tài khoản",
|
||||
"enterRecoveryKeyHint": "Nhập khóa khôi phục của bạn",
|
||||
@@ -154,6 +154,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"invalidQRCode": "Mã QR không hợp lệ",
|
||||
"noRecoveryKeyTitle": "Không có khóa khôi phục?",
|
||||
"enterEmailHint": "Nhập địa chỉ email của bạn",
|
||||
"invalidEmailTitle": "Địa chỉ email không hợp lệ",
|
||||
@@ -177,6 +178,7 @@
|
||||
"security": "Bảo mật",
|
||||
"lockscreen": "Màn hình khoá",
|
||||
"authToChangeLockscreenSetting": "Vui lòng xác thực để thay đổi cài đặt màn hình khóa",
|
||||
"deviceLockEnablePreSteps": "Để bật khoá thiết bị, vui lòng thiết lập mật khẩu thiết bị hoặc khóa màn hình trong cài đặt hệ thống của bạn.",
|
||||
"viewActiveSessions": "Xem danh sách phiên làm việc hiện tại",
|
||||
"authToViewYourActiveSessions": "Vui lòng xác thực để xem danh sách phiên làm việc của bạn",
|
||||
"searchHint": "Tìm kiếm...",
|
||||
@@ -195,6 +197,10 @@
|
||||
"recoveryKeySaveDescription": "Chúng tôi không lưu trữ khóa này, vui lòng lưu khóa 24 từ này ở nơi an toàn.",
|
||||
"doThisLater": "Để sau",
|
||||
"saveKey": "Lưu khóa",
|
||||
"save": "Lưu",
|
||||
"send": "Gửi",
|
||||
"saveOrSendDescription": "Bạn có muốn lưu vào bộ nhớ (Mặc định lưu vào thư mục Tải về) hoặc chuyển qua ứng dụng khác?",
|
||||
"saveOnlyDescription": "Bạn có muốn lưu vào bộ nhớ không (Mặc định lưu vào thư mục Tải về)?",
|
||||
"back": "Quay lại",
|
||||
"createAccount": "Tạo tài khoản",
|
||||
"passwordStrength": "Độ mạnh mật khẩu: {passwordStrengthValue}",
|
||||
@@ -253,12 +259,15 @@
|
||||
"exportLogs": "Xuất nhật ký",
|
||||
"enterYourRecoveryKey": "Nhập khóa khôi phục của bạn",
|
||||
"tempErrorContactSupportIfPersists": "Có vẻ như đã xảy ra sự cố. Vui lòng thử lại sau một thời gian. Nếu lỗi vẫn tiếp diễn, vui lòng liên hệ với nhóm hỗ trợ của chúng tôi.",
|
||||
"networkHostLookUpErr": "Không thể kết nối đến Ente, vui lòng kiểm tra lại kết nối mạng. Nếu vẫn còn lỗi, xin vui lòng liên hệ hỗ trợ.",
|
||||
"networkConnectionRefusedErr": "Không thể kết nối đến Ente, vui lòng thử lại sau. Nếu vẫn còn lỗi, xin vui lòng liên hệ hỗ trợ.",
|
||||
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Có vẻ như đã xảy ra sự cố. Vui lòng thử lại sau một thời gian. Nếu lỗi vẫn tiếp diễn, vui lòng liên hệ với nhóm hỗ trợ của chúng tôi.",
|
||||
"about": "Về chúng tôi",
|
||||
"weAreOpenSource": "Chúng tôi có mã nguồn mở!",
|
||||
"privacy": "Riêng tư",
|
||||
"terms": "Điều khoản",
|
||||
"checkForUpdates": "Kiểm tra cập nhật",
|
||||
"checkStatus": "Kiểm tra trạng thái",
|
||||
"downloadUpdate": "Tải xuống",
|
||||
"criticalUpdateAvailable": "Đã có bản cập nhật quan trọng",
|
||||
"updateAvailable": "Đã có bản cập nhật",
|
||||
@@ -342,6 +351,7 @@
|
||||
"deleteCodeAuthMessage": "Xác minh để xóa mã",
|
||||
"showQRAuthMessage": "Xác minh để hiển thị mã QR",
|
||||
"confirmAccountDeleteTitle": "Xác nhận xóa tài khoản",
|
||||
"confirmAccountDeleteMessage": "Tài khoản này được liên kết với các ứng dụng Ente trên các nền tảng khác, nếu bạn có sử dụng.\n\nDữ liệu đã tải lên của bạn, trên mọi nền tảng, sẽ bị lên lịch xóa và tài khoản của bạn sẽ bị xóa vĩnh viễn.",
|
||||
"androidBiometricHint": "Xác định danh tính",
|
||||
"@androidBiometricHint": {
|
||||
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
|
||||
@@ -402,12 +412,51 @@
|
||||
"doNotSignOut": "Không được đăng xuất",
|
||||
"hearUsWhereTitle": "Bạn biết đến Ente bằng cách nào? (không bắt buộc)",
|
||||
"hearUsExplanation": "Chúng tôi không theo dõi lượt cài đặt ứng dụng. Sẽ rất hữu ích nếu bạn cho chúng tôi biết nơi bạn tìm thấy chúng tôi!",
|
||||
"recoveryKeySaved": "Đã lưu khoá dự phòng vào thư mục Tải về!",
|
||||
"waitingForBrowserRequest": "Đang chờ yêu cầu từ trình duyệt...",
|
||||
"waitingForVerification": "Đang chờ xác thực",
|
||||
"passKeyPendingVerification": "Đang chờ xác thực",
|
||||
"loginSessionExpired": "Phiên làm việc hết hạn",
|
||||
"loginSessionExpiredDetails": "Phiên làm việc hết hạn. Vui lòng đăng nhập lại.",
|
||||
"developerSettingsWarning": "Bạn có chắc chắn muốn thay đổi Tuỳ chọn cho nhà phát triển không?",
|
||||
"developerSettings": "Cài đặt cho nhà phát triển",
|
||||
"invalidEndpoint": "Điểm cuối không hợp lệ",
|
||||
"endpointUpdatedMessage": "Cập nhật điểm cuối thành công",
|
||||
"customEndpoint": "Đã kết nối đến",
|
||||
"pinText": "Ghim",
|
||||
"unpinText": "Bỏ ghim",
|
||||
"pinnedCodeMessage": "{code} đã được ghim",
|
||||
"unpinnedCodeMessage": "{code} đã được bỏ ghim",
|
||||
"tags": "Thẻ",
|
||||
"createNewTag": "Tạo thẻ mới",
|
||||
"tag": "Thẻ",
|
||||
"create": "Tạo",
|
||||
"editTag": "Sửa thẻ",
|
||||
"deleteTagTitle": "Xóa thẻ?",
|
||||
"deleteTagMessage": "Bạn có chắc chắn muốn xóa thẻ này không? Hành động này không thể đảo ngược.",
|
||||
"updateNotAvailable": "Cập nhật không khả dụng",
|
||||
"viewRawCodes": "Xem mã nguồn",
|
||||
"rawCodes": "Mã nguồn",
|
||||
"rawCodeData": "Dữ liệu thô",
|
||||
"appLock": "Khóa ứng dụng",
|
||||
"noSystemLockFound": "Không thấy khoá hệ thống",
|
||||
"toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Để bật khoá ứng dụng, vui lòng thiết lập mật khẩu thiết bị hoặc khóa màn hình trong cài đặt hệ thống của bạn.",
|
||||
"autoLock": "Tự động khóa",
|
||||
"immediately": "Tức thì",
|
||||
"reEnterPassword": "Nhập lại mật khẩu",
|
||||
"reEnterPin": "Nhập lại mã PIN",
|
||||
"next": "Tiếp",
|
||||
"tooManyIncorrectAttempts": "Quá nhiều lần thử không chính xác",
|
||||
"tapToUnlock": "Nhấn để mở khóa",
|
||||
"setNewPassword": "Đặt lại mật khẩu",
|
||||
"deviceLock": "Khóa thiết bị",
|
||||
"hideContent": "Ẩn nội dung",
|
||||
"hideContentDescriptionAndroid": "Ẩn nội dung khi chuyển ứng dụng và chặn chụp màn hình",
|
||||
"hideContentDescriptioniOS": "Ẩn nội dung khi chuyển ứng dụng",
|
||||
"autoLockFeatureDescription": "Thời gian ứng dụng tự khoá sau khi ở trạng thái nền",
|
||||
"appLockDescription": "Chọn giữa màn hình khoá mặc định của thiết bị và màn hình khoá tự chọn dùng mã PIN hoặc mật khẩu.",
|
||||
"pinLock": "Mã PIN",
|
||||
"enterPin": "Nhập mã PIN",
|
||||
"setNewPin": "Đổi mã PIN"
|
||||
"setNewPin": "Đổi mã PIN",
|
||||
"importFailureDescNew": "Không thể phân tích file đã chọn."
|
||||
}
|
||||
@@ -19,6 +19,20 @@
|
||||
"pleaseVerifyDetails": "请验证详细信息并重试",
|
||||
"codeIssuerHint": "发行人",
|
||||
"codeSecretKeyHint": "私钥",
|
||||
"secret": "秘密",
|
||||
"all": "全部",
|
||||
"notes": "备注",
|
||||
"notesLengthLimit": "备注最多可以包含 {count} 个字符",
|
||||
"@notesLengthLimit": {
|
||||
"description": "Text to indicate the maximum number of characters allowed for notes",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"description": "The maximum number of characters allowed for notes",
|
||||
"type": "int",
|
||||
"example": "100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codeAccountHint": "账户 (you@domain.com)",
|
||||
"codeTagHint": "标签",
|
||||
"accountKeyType": "密钥类型",
|
||||
@@ -27,15 +41,18 @@
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
},
|
||||
"pleaseLoginAgain": "请重新登录",
|
||||
"loggingOut": "正在退出登录...",
|
||||
"timeBasedKeyType": "基于时间的 (TOTP)",
|
||||
"counterBasedKeyType": "基于计数器的(HOTP)",
|
||||
"loggingOut": "正在登出...",
|
||||
"timeBasedKeyType": "基于时间 (TOTP)",
|
||||
"counterBasedKeyType": "基于计数器 (HOTP)",
|
||||
"saveAction": "保存",
|
||||
"nextTotpTitle": "下一个",
|
||||
"deleteCodeTitle": "要删除代码吗?",
|
||||
"deleteCodeMessage": "您确定要删除此代码吗?此操作是不可逆的。",
|
||||
"deleteCodeMessage": "您确定要删除此代码吗?此操作不可逆。",
|
||||
"trashCode": "要删除代码吗?",
|
||||
"trashCodeMessage": "您确定要删除 {account} 的代码吗?",
|
||||
"trash": "删除",
|
||||
"viewLogsAction": "查看日志",
|
||||
"sendLogsDescription": "这将跨日志发送以帮助我们调试您的问题。 虽然我们采取预防措施以确保不记录敏感信息,但我们鼓励您在共享这些日志之前先查看它们。",
|
||||
"sendLogsDescription": "这将发送日志以帮助我们调试您的问题。虽然我们采取预防措施确保不记录敏感信息,但我们建议您在共享这些日志之前先查看它们。",
|
||||
"preparingLogsTitle": "正在准备日志...",
|
||||
"emailLogsTitle": "电子邮件日志",
|
||||
"emailLogsMessage": "请将日志发送至 {email}",
|
||||
@@ -67,13 +84,13 @@
|
||||
"pleaseWait": "请稍候...",
|
||||
"generatingEncryptionKeysTitle": "正在生成加密密钥...",
|
||||
"recreatePassword": "重新创建密码",
|
||||
"recreatePasswordMessage": "当前设备的强度不足以验证您的密码, 所以我们需要以一种能够与所有设备一起运行的方式重新生成它。 \n\n请使用您的恢复密钥登录并重新生成您的密码 (如果您愿意,您可以再次使用相同密钥)。",
|
||||
"recreatePasswordMessage": "当前设备的功能不足以验证您的密码,因此我们需要以一种适用于所有设备的方式重新生成一次密码。\n\n请使用您的恢复密钥登录并重新生成您的密码(如果您愿意,可以再次使用相同的密码)。",
|
||||
"useRecoveryKey": "使用恢复密钥",
|
||||
"incorrectPasswordTitle": "密码错误",
|
||||
"welcomeBack": "欢迎回来!",
|
||||
"madeWithLoveAtPrefix": "用❤️制成 ",
|
||||
"supportDevs": "订阅 <bold-green>ente</bold-green> 以支持此项目。",
|
||||
"supportDiscount": "使用优惠券号码“AUTH”获得第一年优惠10%的折扣",
|
||||
"supportDiscount": "使用优惠码“AUTH”可享受首年 10% 折扣",
|
||||
"changeEmail": "修改邮箱",
|
||||
"changePassword": "修改密码",
|
||||
"data": "数据",
|
||||
@@ -83,29 +100,30 @@
|
||||
"passwordForDecryptingExport": "用来解密导出的密码",
|
||||
"passwordEmptyError": "密码不能为空",
|
||||
"importFromApp": "从 {appName} 导入代码",
|
||||
"importGoogleAuthGuide": "使用“转移帐户”选项将您的帐户从 Google 身份验证器导出到二维码。然后使用另一台设备扫描二维码。\n\n提示:您可以使用笔记本电脑的网络摄像头拍摄二维码的照片。",
|
||||
"importGoogleAuthGuide": "使用“转移账户”选项将您的账户从 Google Authenticator 导出到二维码。然后使用另一台设备扫描二维码。\n\n提示:您可以使用笔记本电脑的摄像头拍摄二维码的照片。",
|
||||
"importSelectJsonFile": "选择 JSON 文件",
|
||||
"importSelectAppExport": "选择 {appName} 的导出文件",
|
||||
"importEnteEncGuide": "选择从 Ente 导出的 JSON 加密文件",
|
||||
"importRaivoGuide": "使用 Raivo 设置中的“将 OTP 导出到 Zip 存档”选项。\n\n解压 zip 文件并导入 JSON 文件。",
|
||||
"importBitwardenGuide": "使用 Bitwarden 工具中的“导出保管库”选项并导入未加密的 JSON 文件。",
|
||||
"importAegisGuide": "在Aegis的设置中使用\"导出密码库\"选项。\n\n如果您的密码库已加密,您需要输入密码才能解密密码库。",
|
||||
"import2FasGuide": "使用 2FAS 中的“设置 -> 备份 - 导出”选项。\n\n如果您的备份已被加密,则需要输入密码才能解密备份",
|
||||
"importBitwardenGuide": "使用 Bitwarden 工具中的“导出密码库”选项并导入未加密的 JSON 文件。",
|
||||
"importAegisGuide": "使用 Aegis 设置中的“导出密码库”选项。\n\n如果您的密码库已加密,则需要输入密码库密码才能解密密码库。",
|
||||
"import2FasGuide": "使用 2FAS 中的“设置 -> 备份 -> 导出”选项。\n\n如果您的备份已加密,则需要输入密码来解密备份",
|
||||
"importLastpassGuide": "使用 Lastpass Authenticator 设置中的“转移账户”选项,然后按“将账户导出到文件”。导入下载的 JSON。",
|
||||
"exportCodes": "导出代码",
|
||||
"importLabel": "导入",
|
||||
"importInstruction": "请以以下格式选择包含代码列表的文件",
|
||||
"importInstruction": "请选择一个包含以下格式的代码列表的文件",
|
||||
"importCodeDelimiterInfo": "代码可以用逗号或新行分隔。",
|
||||
"selectFile": "选择文件",
|
||||
"emailVerificationToggle": "电子邮件验证",
|
||||
"emailVerificationEnableWarning": "如果您将 2FA 存储到我们的电子邮件中,则打开电子邮件验证可能会导致僵局。如果您被一项服务锁定,您可能无法登录另一项服务。",
|
||||
"emailVerificationEnableWarning": "为避免被锁在您的账户之外,请在启用电子邮件验证之前确保在 Ente Auth 之外存储电子邮件双重验证的副本。",
|
||||
"authToChangeEmailVerificationSetting": "请进行身份验证以更改电子邮件验证",
|
||||
"authenticateGeneric": "请验证",
|
||||
"authToViewYourRecoveryKey": "请验证以查看您的恢复密钥",
|
||||
"authToChangeYourEmail": "请验证以更改您的电子邮件",
|
||||
"authToChangeYourPassword": "请验证以更改密码",
|
||||
"authToViewSecrets": "请进行身份验证以查看您的秘密",
|
||||
"authToViewSecrets": "请进行身份验证以查看您的密钥",
|
||||
"authToInitiateSignIn": "请进行身份验证以启动登录进行备份。",
|
||||
"ok": "好的",
|
||||
"ok": "确定",
|
||||
"cancel": "取消",
|
||||
"yes": "是",
|
||||
"no": "否",
|
||||
@@ -125,8 +143,8 @@
|
||||
"faq": "常见问题",
|
||||
"faq_q_1": "Auth 的安全性如何?",
|
||||
"faq_a_1": "您通过 Auth 备份的所有代码均以端到端加密方式存储。这意味着只有您可以访问您的代码。我们的应用程序是开源的并且我们的加密技术已经过外部审计。",
|
||||
"faq_q_2": "我可以在桌面上访问我的代码吗?",
|
||||
"faq_a_2": "您可以在 web @auth.ente.io 上访问您的代码。",
|
||||
"faq_q_2": "我可以在桌面设备上访问我的代码吗?",
|
||||
"faq_a_2": "您可以在网页 auth.ente.io 上访问您的代码。",
|
||||
"faq_q_3": "我如何删除代码?",
|
||||
"faq_a_3": "您可以通过向左滑动该项目来删除该代码。",
|
||||
"faq_q_4": "我该如何支持该项目?",
|
||||
@@ -137,7 +155,6 @@
|
||||
"leaveFamily": "离开家庭",
|
||||
"leaveFamilyMessage": "您确定要离开家庭计划吗?",
|
||||
"inFamilyPlanMessage": "你在一个家庭计划中!",
|
||||
"swipeHint": "向左滑动以编辑或删除代码",
|
||||
"scan": "扫描",
|
||||
"scanACode": "扫描代码",
|
||||
"verify": "验证",
|
||||
@@ -193,6 +210,10 @@
|
||||
"scanAQrCode": "扫描二维码",
|
||||
"enterDetailsManually": "手动输入详细信息",
|
||||
"edit": "编辑",
|
||||
"share": "分享",
|
||||
"shareCodes": "分享代码",
|
||||
"shareCodesDuration": "选择您要分享代码的期限。",
|
||||
"restore": "恢复",
|
||||
"copiedToClipboard": "已复制到剪贴板",
|
||||
"copiedNextToClipboard": "已将下一个代码复制到剪贴板",
|
||||
"error": "错误",
|
||||
@@ -240,9 +261,9 @@
|
||||
"ackPasswordLostWarning": "我明白,如果我丢失密码,我可能会丢失我的数据,因为我的数据是 <underline>端到端加密的</underline>。",
|
||||
"loginTerms": "点击登录后,我同意 <u-terms>服务条款</u-terms> 和 <u-policy>隐私政策</u-policy>",
|
||||
"logInLabel": "登录",
|
||||
"logout": "退出登录",
|
||||
"areYouSureYouWantToLogout": "您确定要退出登录吗?",
|
||||
"yesLogout": "是的,退出登陆",
|
||||
"logout": "登出",
|
||||
"areYouSureYouWantToLogout": "您确定要登出吗?",
|
||||
"yesLogout": "是的,登出",
|
||||
"exit": "退出",
|
||||
"verifyingRecoveryKey": "正在验证恢复密钥...",
|
||||
"recoveryKeyVerified": "恢复密钥已验证",
|
||||
@@ -299,7 +320,7 @@
|
||||
"sorry": "抱歉",
|
||||
"importFailureDesc": "无法解析选定的文件。\n如果您需要帮助,请写入support@ente.io!",
|
||||
"pendingSyncs": "警告",
|
||||
"pendingSyncsWarningBody": "您的一些代码尚未备份。\n\n请确保您在退出登录之前备份这些代码。",
|
||||
"pendingSyncsWarningBody": "您的一些代码尚未备份。\n\n请确保您在登出之前备份这些代码。",
|
||||
"checkInboxAndSpamFolder": "请检查您的收件箱 (或者是在您的“垃圾邮件”列表内) 以完成验证",
|
||||
"tapToEnterCode": "点击以输入代码",
|
||||
"resendEmail": "重新发送电子邮件",
|
||||
@@ -316,8 +337,8 @@
|
||||
},
|
||||
"activeSessions": "已登录的设备",
|
||||
"somethingWentWrongPleaseTryAgain": "出了点问题,请重试",
|
||||
"thisWillLogYouOutOfThisDevice": "这将使您在此设备上退出登录!",
|
||||
"thisWillLogYouOutOfTheFollowingDevice": "这将使您在以下设备中退出登录:",
|
||||
"thisWillLogYouOutOfThisDevice": "这将使您登出该设备!",
|
||||
"thisWillLogYouOutOfTheFollowingDevice": "这将使您登出以下设备:",
|
||||
"terminateSession": "是否终止会话?",
|
||||
"terminate": "终止",
|
||||
"thisDevice": "此设备",
|
||||
@@ -346,6 +367,7 @@
|
||||
"sigInBackupReminder": "请导出您的代码以确保您有可以恢复的备份。",
|
||||
"offlineModeWarning": "您已选择在不进行备份的情况下继续操作。请手动备份以确保您的代码安全。",
|
||||
"showLargeIcons": "显示大图标",
|
||||
"compactMode": "紧凑模式",
|
||||
"shouldHideCode": "隐藏代码",
|
||||
"doubleTapToViewHiddenCode": "您可以双击条目来查看代码",
|
||||
"focusOnSearchBar": "应用启动后聚焦搜索",
|
||||
@@ -396,7 +418,7 @@
|
||||
"@androidGoToSettingsDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side."
|
||||
},
|
||||
"iOSLockOut": "生物识别身份验证已禁用。请锁定再解锁您的屏幕以启用它。",
|
||||
"iOSLockOut": "生物识别身份验证已禁用。请锁定并解锁屏幕以启用该功能。",
|
||||
"@iOSLockOut": {
|
||||
"description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side."
|
||||
},
|
||||
@@ -410,11 +432,11 @@
|
||||
},
|
||||
"noInternetConnection": "无互联网连接",
|
||||
"pleaseCheckYourInternetConnectionAndTryAgain": "请检查您的互联网连接,然后重试。",
|
||||
"signOutFromOtherDevices": "从其他设备退出登录",
|
||||
"signOutOtherBody": "如果你认为有人可能知道你的密码,你可以强制所有使用你账户的其他设备退出登录。",
|
||||
"signOutFromOtherDevices": "从其他设备登出",
|
||||
"signOutOtherBody": "如果您认为有人可能知道您的密码,您可以强制所有其他使用您账户的设备登出。",
|
||||
"signOutOtherDevices": "登出其他设备",
|
||||
"doNotSignOut": "不要退登",
|
||||
"hearUsWhereTitle": "您是如何知道Ente的? (可选的)",
|
||||
"doNotSignOut": "不要登出",
|
||||
"hearUsWhereTitle": "您是怎么知道 Ente 的?(可选)",
|
||||
"hearUsExplanation": "我们不跟踪应用程序安装情况。如果您告诉我们您是在哪里找到我们的,将会有所帮助!",
|
||||
"recoveryKeySaved": "恢复密钥已保存在下载文件夹中!",
|
||||
"waitingForBrowserRequest": "正在等待浏览器请求...",
|
||||
@@ -466,5 +488,7 @@
|
||||
"pinLock": "Pin 锁定",
|
||||
"enterPin": "输入 PIN 码",
|
||||
"setNewPin": "设置新 PIN 码",
|
||||
"importFailureDescNew": "无法解析选定的文件。"
|
||||
"importFailureDescNew": "无法解析选定的文件。",
|
||||
"appLockNotEnabled": "应用锁未启用",
|
||||
"appLockNotEnabledDescription": "请从“安全”>“应用锁”启用应用锁"
|
||||
}
|
||||
@@ -27,6 +27,8 @@ class Code {
|
||||
|
||||
bool get isPinned => display.pinned;
|
||||
|
||||
bool get isTrashed => display.trashed;
|
||||
|
||||
final Object? err;
|
||||
bool get hasError => err != null;
|
||||
|
||||
@@ -81,6 +83,7 @@ class Code {
|
||||
final Type updatedType = type ?? this.type;
|
||||
final int updatedCounter = counter ?? this.counter;
|
||||
final CodeDisplay updatedDisplay = display ?? this.display;
|
||||
final String encodedIssuer = Uri.encodeQueryComponent(updateIssuer);
|
||||
|
||||
return Code(
|
||||
updateAccount,
|
||||
@@ -92,7 +95,7 @@ class Code {
|
||||
updatedType,
|
||||
updatedCounter,
|
||||
"otpauth://${updatedType.name}/$updateIssuer:$updateAccount?algorithm=${updatedAlgo.name}"
|
||||
"&digits=$updatedDigits&issuer=$updateIssuer"
|
||||
"&digits=$updatedDigits&issuer=$encodedIssuer"
|
||||
"&period=$updatePeriod&secret=$updatedSecret${updatedType == Type.hotp ? "&counter=$updatedCounter" : ""}",
|
||||
generatedID: generatedID,
|
||||
display: updatedDisplay,
|
||||
@@ -107,6 +110,7 @@ class Code {
|
||||
CodeDisplay? display,
|
||||
int digits,
|
||||
) {
|
||||
final String encodedIssuer = Uri.encodeQueryComponent(issuer);
|
||||
return Code(
|
||||
account,
|
||||
issuer,
|
||||
@@ -116,7 +120,7 @@ class Code {
|
||||
Algorithm.sha1,
|
||||
type,
|
||||
0,
|
||||
"otpauth://${type.name}/$issuer:$account?algorithm=SHA1&digits=$digits&issuer=$issuer&period=30&secret=$secret",
|
||||
"otpauth://${type.name}/$issuer:$account?algorithm=SHA1&digits=$digits&issuer=$encodedIssuer&period=30&secret=$secret",
|
||||
display: display ?? CodeDisplay(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ class CodeDisplay {
|
||||
final bool trashed;
|
||||
final int lastUsedAt;
|
||||
final int tapCount;
|
||||
String note;
|
||||
final List<String> tags;
|
||||
|
||||
CodeDisplay({
|
||||
@@ -17,6 +18,7 @@ class CodeDisplay {
|
||||
this.lastUsedAt = 0,
|
||||
this.tapCount = 0,
|
||||
this.tags = const [],
|
||||
this.note = '',
|
||||
});
|
||||
|
||||
// copyWith
|
||||
@@ -26,12 +28,14 @@ class CodeDisplay {
|
||||
int? lastUsedAt,
|
||||
int? tapCount,
|
||||
List<String>? tags,
|
||||
String? note,
|
||||
}) {
|
||||
final bool updatedPinned = pinned ?? this.pinned;
|
||||
final bool updatedTrashed = trashed ?? this.trashed;
|
||||
final int updatedLastUsedAt = lastUsedAt ?? this.lastUsedAt;
|
||||
final int updatedTapCount = tapCount ?? this.tapCount;
|
||||
final List<String> updatedTags = tags ?? this.tags;
|
||||
final String updatedNote = note ?? this.note;
|
||||
|
||||
return CodeDisplay(
|
||||
pinned: updatedPinned,
|
||||
@@ -39,6 +43,7 @@ class CodeDisplay {
|
||||
lastUsedAt: updatedLastUsedAt,
|
||||
tapCount: updatedTapCount,
|
||||
tags: updatedTags,
|
||||
note: updatedNote,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,6 +57,7 @@ class CodeDisplay {
|
||||
lastUsedAt: json['lastUsedAt'] ?? 0,
|
||||
tapCount: json['tapCount'] ?? 0,
|
||||
tags: List<String>.from(json['tags'] ?? []),
|
||||
note: json['note'] ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -92,6 +98,7 @@ class CodeDisplay {
|
||||
'lastUsedAt': lastUsedAt,
|
||||
'tapCount': tapCount,
|
||||
'tags': tags,
|
||||
'note': note,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -104,6 +111,7 @@ class CodeDisplay {
|
||||
other.trashed == trashed &&
|
||||
other.lastUsedAt == lastUsedAt &&
|
||||
other.tapCount == tapCount &&
|
||||
other.note == note &&
|
||||
listEquals(other.tags, tags);
|
||||
}
|
||||
|
||||
@@ -113,6 +121,7 @@ class CodeDisplay {
|
||||
trashed.hashCode ^
|
||||
lastUsedAt.hashCode ^
|
||||
tapCount.hashCode ^
|
||||
note.hashCode ^
|
||||
tags.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
25
auth/lib/onboarding/view/common/field_label.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FieldLabel extends StatelessWidget {
|
||||
final String label;
|
||||
|
||||
const FieldLabel(
|
||||
this.label, {
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 12.0),
|
||||
child: SizedBox(
|
||||
width: 80,
|
||||
child: Text(
|
||||
label,
|
||||
style: getEnteTextTheme(context).miniBoldMuted,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ class TagChip extends StatelessWidget {
|
||||
final VoidCallback? onTap;
|
||||
final TagChipState state;
|
||||
final TagChipAction action;
|
||||
final IconData? iconData;
|
||||
|
||||
const TagChip({
|
||||
super.key,
|
||||
@@ -17,11 +18,16 @@ class TagChip extends StatelessWidget {
|
||||
this.state = TagChipState.unselected,
|
||||
this.action = TagChipAction.none,
|
||||
this.onTap,
|
||||
this.iconData,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = getEnteColorScheme(context);
|
||||
final color = state == TagChipState.selected ||
|
||||
Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.white
|
||||
: colorScheme.tagTextUnselectedColor;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
@@ -51,15 +57,24 @@ class TagChip extends StatelessWidget {
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaler: const TextScaler.linear(1),
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: state == TagChipState.selected ||
|
||||
Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.white
|
||||
: colorScheme.tagTextUnselectedColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
if (iconData != null) ...[
|
||||
Icon(
|
||||
iconData,
|
||||
size: 16,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: color,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (state == TagChipState.selected &&
|
||||
|
||||
@@ -8,13 +8,17 @@ import 'package:ente_auth/models/code_display.dart';
|
||||
import 'package:ente_auth/onboarding/model/tag_enums.dart';
|
||||
import 'package:ente_auth/onboarding/view/common/add_chip.dart';
|
||||
import 'package:ente_auth/onboarding/view/common/add_tag.dart';
|
||||
import 'package:ente_auth/onboarding/view/common/field_label.dart';
|
||||
import 'package:ente_auth/onboarding/view/common/tag_chip.dart';
|
||||
import 'package:ente_auth/store/code_display_store.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
|
||||
import 'package:ente_auth/ui/components/models/button_result.dart';
|
||||
import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:ente_auth/utils/toast_util.dart';
|
||||
import 'package:ente_auth/utils/totp_util.dart';
|
||||
import "package:flutter/material.dart";
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
class SetupEnterSecretKeyPage extends StatefulWidget {
|
||||
final Code? code;
|
||||
@@ -27,11 +31,15 @@ class SetupEnterSecretKeyPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
|
||||
final Logger _logger = Logger('_SetupEnterSecretKeyPageState');
|
||||
final int _notesLimit = 500;
|
||||
final int _otherTextLimit = 200;
|
||||
late TextEditingController _issuerController;
|
||||
late TextEditingController _accountController;
|
||||
late TextEditingController _secretController;
|
||||
late TextEditingController _notesController;
|
||||
late bool _secretKeyObscured;
|
||||
late List<String> tags = [...?widget.code?.display.tags];
|
||||
late List<String> selectedTags = [...?widget.code?.display.tags];
|
||||
List<String> allTags = [];
|
||||
StreamSubscription<CodesUpdatedEvent>? _streamSubscription;
|
||||
|
||||
@@ -47,17 +55,52 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
|
||||
_secretController = TextEditingController(
|
||||
text: widget.code?.secret,
|
||||
);
|
||||
_notesController = TextEditingController(
|
||||
text: widget.code?.display.note,
|
||||
);
|
||||
_secretKeyObscured = widget.code != null;
|
||||
_loadTags();
|
||||
_streamSubscription = Bus.instance.on<CodesUpdatedEvent>().listen((event) {
|
||||
_loadTags();
|
||||
});
|
||||
_notesController.addListener(() {
|
||||
if (_notesController.text.length > _notesLimit) {
|
||||
_notesController.text = _notesController.text.substring(0, _notesLimit);
|
||||
_notesController.selection = TextSelection.fromPosition(
|
||||
TextPosition(offset: _notesController.text.length),
|
||||
);
|
||||
showToast(context, context.l10n.notesLengthLimit(_notesLimit));
|
||||
}
|
||||
});
|
||||
|
||||
if (widget.code == null ||
|
||||
(widget.code!.issuer.length < _otherTextLimit &&
|
||||
widget.code!.account.length < _otherTextLimit &&
|
||||
widget.code!.secret.length < _otherTextLimit)) {
|
||||
_limitTextLength(_issuerController, _otherTextLimit);
|
||||
_limitTextLength(_accountController, _otherTextLimit);
|
||||
_limitTextLength(_secretController, _otherTextLimit);
|
||||
}
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void _limitTextLength(TextEditingController controller, int limit) {
|
||||
controller.addListener(() {
|
||||
if (controller.text.length > limit) {
|
||||
controller.text = controller.text.substring(0, limit);
|
||||
controller.selection = TextSelection.fromPosition(
|
||||
TextPosition(offset: controller.text.length),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_streamSubscription?.cancel();
|
||||
_issuerController.dispose();
|
||||
_accountController.dispose();
|
||||
_notesController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -72,163 +115,197 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(l10n.importAccountPageTitle),
|
||||
),
|
||||
body: Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 40.0, horizontal: 40),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TextFormField(
|
||||
// The validator receives the text that the user has entered.
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Please enter some text";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: l10n.codeIssuerHint,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.auto,
|
||||
labelText: l10n.codeIssuerHint,
|
||||
),
|
||||
controller: _issuerController,
|
||||
autofocus: true,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
TextFormField(
|
||||
// The validator receives the text that the user has entered.
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Please enter some text";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: l10n.codeSecretKeyHint,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.auto,
|
||||
labelText: l10n.codeSecretKeyHint,
|
||||
suffixIcon: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_secretKeyObscured = !_secretKeyObscured;
|
||||
});
|
||||
},
|
||||
icon: _secretKeyObscured
|
||||
? const Icon(Icons.visibility_off_rounded)
|
||||
: const Icon(Icons.visibility_rounded),
|
||||
),
|
||||
),
|
||||
obscureText: _secretKeyObscured,
|
||||
controller: _secretController,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
TextFormField(
|
||||
// The validator receives the text that the user has entered.
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Please enter some text";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: l10n.codeAccountHint,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.auto,
|
||||
labelText: l10n.codeAccountHint,
|
||||
),
|
||||
controller: _accountController,
|
||||
),
|
||||
const SizedBox(height: 40),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text(
|
||||
l10n.tags,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
alignment: WrapAlignment.start,
|
||||
children: [
|
||||
...allTags.map(
|
||||
(e) => TagChip(
|
||||
label: e,
|
||||
action: TagChipAction.check,
|
||||
state: tags.contains(e)
|
||||
? TagChipState.selected
|
||||
: TagChipState.unselected,
|
||||
onTap: () {
|
||||
if (tags.contains(e)) {
|
||||
tags.remove(e);
|
||||
} else {
|
||||
tags.add(e);
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
AddChip(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AddTagDialog(
|
||||
onTap: (tag) {
|
||||
if (allTags.contains(tag) &&
|
||||
tags.contains(tag)) {
|
||||
return;
|
||||
}
|
||||
allTags.add(tag);
|
||||
tags.add(tag);
|
||||
setState(() {});
|
||||
Navigator.pop(context);
|
||||
},
|
||||
);
|
||||
},
|
||||
barrierColor: Colors.black.withOpacity(0.85),
|
||||
barrierDismissible: false,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: () async {
|
||||
if ((_accountController.text.trim().isEmpty &&
|
||||
_issuerController.text.trim().isEmpty) ||
|
||||
_secretController.text.trim().isEmpty) {
|
||||
String message;
|
||||
if (_secretController.text.trim().isEmpty) {
|
||||
message = context.l10n.secretCanNotBeEmpty;
|
||||
} else {
|
||||
message =
|
||||
context.l10n.bothIssuerAndAccountCanNotBeEmpty;
|
||||
appBar: AppBar(title: Text(l10n.importAccountPageTitle)),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
FieldLabel(l10n.codeIssuerHint),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
// The validator receives the text that the user has entered.
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Please enter some text";
|
||||
}
|
||||
_showIncorrectDetailsDialog(context, message: message);
|
||||
return;
|
||||
}
|
||||
await _saveCode();
|
||||
},
|
||||
child: Text(l10n.saveAction),
|
||||
return null;
|
||||
},
|
||||
decoration: const InputDecoration(
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 12.0),
|
||||
),
|
||||
style: getEnteTextTheme(context).small,
|
||||
controller: _issuerController,
|
||||
autofocus: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
FieldLabel(l10n.secret),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
// The validator receives the text that the user has entered.
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Please enter some text";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
style: getEnteTextTheme(context).small,
|
||||
decoration: InputDecoration(
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(vertical: 12.0),
|
||||
suffixIcon: GestureDetector(
|
||||
// padding: EdgeInsets.zero,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_secretKeyObscured = !_secretKeyObscured;
|
||||
});
|
||||
},
|
||||
child: _secretKeyObscured
|
||||
? const Icon(
|
||||
Icons.visibility_off_rounded,
|
||||
size: 18,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.visibility_rounded,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
obscureText: _secretKeyObscured,
|
||||
controller: _secretController,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
FieldLabel(l10n.account),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
// The validator receives the text that the user has entered.
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Please enter some text";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
decoration: const InputDecoration(
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 12.0),
|
||||
),
|
||||
style: getEnteTextTheme(context).small,
|
||||
controller: _accountController,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
FieldLabel(l10n.notes),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
// The validator receives the text that the user has entered.
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Please enter some text";
|
||||
}
|
||||
if (value.length > _notesLimit) {
|
||||
return "Notes can't be more than 1000 characters";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
maxLength: _notesLimit,
|
||||
minLines: 1,
|
||||
maxLines: 5,
|
||||
decoration: const InputDecoration(
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 12.0),
|
||||
),
|
||||
style: getEnteTextTheme(context).small,
|
||||
controller: _notesController,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
alignment: WrapAlignment.start,
|
||||
children: [
|
||||
...allTags.map(
|
||||
(e) => TagChip(
|
||||
label: e,
|
||||
action: TagChipAction.check,
|
||||
state: selectedTags.contains(e)
|
||||
? TagChipState.selected
|
||||
: TagChipState.unselected,
|
||||
onTap: () {
|
||||
if (selectedTags.contains(e)) {
|
||||
selectedTags.remove(e);
|
||||
} else {
|
||||
selectedTags.add(e);
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
AddChip(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AddTagDialog(
|
||||
onTap: (tag) {
|
||||
final exist = allTags.contains(tag);
|
||||
if (exist && selectedTags.contains(tag)) {
|
||||
return Navigator.pop(context);
|
||||
}
|
||||
if (!exist) allTags.add(tag);
|
||||
selectedTags.add(tag);
|
||||
setState(() {});
|
||||
Navigator.pop(context);
|
||||
},
|
||||
);
|
||||
},
|
||||
barrierColor: Colors.black.withOpacity(0.85),
|
||||
barrierDismissible: false,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: () async {
|
||||
if ((_accountController.text.trim().isEmpty &&
|
||||
_issuerController.text.trim().isEmpty) ||
|
||||
_secretController.text.trim().isEmpty) {
|
||||
String message;
|
||||
if (_secretController.text.trim().isEmpty) {
|
||||
message = context.l10n.secretCanNotBeEmpty;
|
||||
} else {
|
||||
message =
|
||||
context.l10n.bothIssuerAndAccountCanNotBeEmpty;
|
||||
}
|
||||
_showIncorrectDetailsDialog(context, message: message);
|
||||
return;
|
||||
}
|
||||
await _saveCode();
|
||||
},
|
||||
child: Text(l10n.saveAction),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -240,7 +317,13 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
|
||||
final account = _accountController.text.trim();
|
||||
final issuer = _issuerController.text.trim();
|
||||
final secret = _secretController.text.trim().replaceAll(' ', '');
|
||||
final isStreamCode = issuer.toLowerCase() == "steam" || issuer.toLowerCase().contains('steampowered.com');
|
||||
final notes = _notesController.text.trim();
|
||||
final isStreamCode = issuer.toLowerCase() == "steam" ||
|
||||
issuer.toLowerCase().contains('steampowered.com');
|
||||
final CodeDisplay display =
|
||||
widget.code?.display.copyWith(tags: selectedTags) ??
|
||||
CodeDisplay(tags: selectedTags);
|
||||
display.note = notes;
|
||||
if (widget.code != null && widget.code!.secret != secret) {
|
||||
ButtonResult? result = await showChoiceActionSheet(
|
||||
context,
|
||||
@@ -255,8 +338,7 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
final CodeDisplay display =
|
||||
widget.code?.display.copyWith(tags: tags) ?? CodeDisplay(tags: tags);
|
||||
|
||||
final Code newCode = widget.code == null
|
||||
? Code.fromAccountAndSecret(
|
||||
isStreamCode ? Type.steam : Type.totp,
|
||||
@@ -275,7 +357,8 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
|
||||
// Verify the validity of the code
|
||||
getOTP(newCode);
|
||||
Navigator.of(context).pop(newCode);
|
||||
} catch (e) {
|
||||
} catch (e, s) {
|
||||
_logger.severe("Error saving code", e, s);
|
||||
_showIncorrectDetailsDialog(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ class ViewQrPage extends StatelessWidget {
|
||||
data: code!.rawData,
|
||||
eyeStyle: QrEyeStyle(
|
||||
eyeShape: QrEyeShape.square,
|
||||
color: Theme.of(context).colorScheme.onBackground,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
dataModuleStyle: QrDataModuleStyle(
|
||||
dataModuleShape: QrDataModuleShape.square,
|
||||
color: Theme.of(context).colorScheme.onBackground,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
version: QrVersions.auto,
|
||||
size: qrSize,
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:ente_auth/utils/auth_util.dart';
|
||||
import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:ente_auth/utils/lock_screen_settings.dart';
|
||||
import 'package:ente_auth/utils/toast_util.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_local_authentication/flutter_local_authentication.dart';
|
||||
@@ -19,11 +20,19 @@ class LocalAuthenticationService {
|
||||
static final LocalAuthenticationService instance =
|
||||
LocalAuthenticationService._privateConstructor();
|
||||
final logger = Logger((LocalAuthenticationService).toString());
|
||||
int lastAuthTime = 0;
|
||||
|
||||
Future<bool> requestLocalAuthentication(
|
||||
BuildContext context,
|
||||
String infoMessage,
|
||||
) async {
|
||||
if (kDebugMode) {
|
||||
// if last auth time is less than 60 seconds, don't ask for auth again
|
||||
if (lastAuthTime != 0 &&
|
||||
DateTime.now().millisecondsSinceEpoch - lastAuthTime < 60000) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (await isLocalAuthSupportedOnDevice() ||
|
||||
LockScreenSettings.instance.getIsAppLockSet()) {
|
||||
AppLock.of(context)!.setEnabled(false);
|
||||
@@ -39,6 +48,7 @@ class LocalAuthenticationService {
|
||||
showToast(context, infoMessage);
|
||||
return false;
|
||||
} else {
|
||||
lastAuthTime = DateTime.now().millisecondsSinceEpoch;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,12 @@ class PreferenceService {
|
||||
|
||||
late final SharedPreferences _prefs;
|
||||
|
||||
static const kHasShownCoachMarkKey = "has_shown_coach_mark";
|
||||
static const kHasShownCoachMarkKey = "has_shown_coach_mark_v2";
|
||||
static const kShouldShowLargeIconsKey = "should_show_large_icons";
|
||||
static const kShouldHideCodesKey = "should_hide_codes";
|
||||
static const kShouldAutoFocusOnSearchBar = "should_auto_focus_on_search_bar";
|
||||
static const kShouldMinimizeOnCopy = "should_minimize_on_copy";
|
||||
static const kCompactMode = "vi.compactMode";
|
||||
|
||||
Future<void> init() async {
|
||||
_prefs = await SharedPreferences.getInstance();
|
||||
@@ -48,6 +49,14 @@ class PreferenceService {
|
||||
return _prefs.getBool(kShouldHideCodesKey) ?? false;
|
||||
}
|
||||
|
||||
bool isCompactMode() {
|
||||
return _prefs.getBool(kCompactMode) ?? false;
|
||||
}
|
||||
|
||||
Future<void> setCompactMode(bool value) async {
|
||||
await _prefs.setBool(kCompactMode, value);
|
||||
}
|
||||
|
||||
Future<void> setHideCodes(bool value) async {
|
||||
await _prefs.setBool(kShouldHideCodesKey, value);
|
||||
Bus.instance.fire(IconsChangedEvent());
|
||||
|
||||
@@ -585,9 +585,8 @@ class UserService {
|
||||
final clientS = client.calculateSecret(serverB);
|
||||
final clientM = client.calculateClientEvidenceMessage();
|
||||
|
||||
late Response _;
|
||||
if (setKeysRequest == null) {
|
||||
_ = await _enteDio.post(
|
||||
await _enteDio.post(
|
||||
"/users/srp/complete",
|
||||
data: {
|
||||
'setupID': setupSRPResponse.setupID,
|
||||
@@ -595,7 +594,7 @@ class UserService {
|
||||
},
|
||||
);
|
||||
} else {
|
||||
_ = await _enteDio.post(
|
||||
await _enteDio.post(
|
||||
"/users/srp/update",
|
||||
data: {
|
||||
'setupID': setupSRPResponse.setupID,
|
||||
|
||||
@@ -30,6 +30,7 @@ class CodeDisplayStore {
|
||||
final tags = <String>{};
|
||||
for (final code in codes) {
|
||||
if (code.hasError) continue;
|
||||
if (code.isTrashed) continue;
|
||||
tags.addAll(code.display.tags);
|
||||
}
|
||||
return tags.toList()..sort();
|
||||
|
||||
@@ -1,61 +1,106 @@
|
||||
import 'package:ente_auth/services/preference_service.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:ente_auth/ui/linear_progress_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
|
||||
class CodeTimerProgressCache {
|
||||
static final Map<int, CodeTimerProgress> _cache = {};
|
||||
|
||||
static CodeTimerProgress getCachedWidget(int period) {
|
||||
if (!_cache.containsKey(period)) {
|
||||
_cache[period] = CodeTimerProgress(period: period);
|
||||
}
|
||||
return _cache[period]!;
|
||||
}
|
||||
}
|
||||
|
||||
class CodeTimerProgress extends StatefulWidget {
|
||||
final int period;
|
||||
|
||||
CodeTimerProgress({
|
||||
const CodeTimerProgress({
|
||||
super.key,
|
||||
required this.period,
|
||||
});
|
||||
|
||||
@override
|
||||
State createState() => _CodeTimerProgressState();
|
||||
State<CodeTimerProgress> createState() => _CodeTimerProgressState();
|
||||
}
|
||||
|
||||
class _CodeTimerProgressState extends State<CodeTimerProgress>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final Ticker _ticker;
|
||||
double _progress = 0.0;
|
||||
late final ValueNotifier<double> _progress;
|
||||
late final int _microSecondsInPeriod;
|
||||
late bool _isCompactMode=false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_microSecondsInPeriod = widget.period * 1000000;
|
||||
_ticker = createTicker((elapsed) {
|
||||
_updateTimeRemaining();
|
||||
});
|
||||
_progress = ValueNotifier<double>(0.0);
|
||||
_ticker = createTicker(_updateTimeRemaining);
|
||||
_ticker.start();
|
||||
_updateTimeRemaining();
|
||||
_isCompactMode = PreferenceService.instance.isCompactMode();
|
||||
_updateTimeRemaining(Duration.zero);
|
||||
}
|
||||
|
||||
void _updateTimeRemaining() {
|
||||
int timeRemaining = (_microSecondsInPeriod) -
|
||||
void _updateTimeRemaining(Duration elapsed) {
|
||||
int timeRemaining = _microSecondsInPeriod -
|
||||
(DateTime.now().microsecondsSinceEpoch % _microSecondsInPeriod);
|
||||
setState(() {
|
||||
_progress = (timeRemaining / _microSecondsInPeriod);
|
||||
});
|
||||
_progress.value = timeRemaining / _microSecondsInPeriod;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_ticker.dispose();
|
||||
_progress.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: 3,
|
||||
child: LinearProgressWidget(
|
||||
color: _progress > 0.4
|
||||
? getEnteColorScheme(context).primary700
|
||||
: Colors.orange,
|
||||
fractionOfStorage: _progress,
|
||||
height: _isCompactMode ?1:3,
|
||||
child: ValueListenableBuilder<double>(
|
||||
valueListenable: _progress,
|
||||
builder: (context, progress, _) {
|
||||
return CustomPaint(
|
||||
painter: _ProgressPainter(
|
||||
progress: progress,
|
||||
color: progress > 0.4
|
||||
? getEnteColorScheme(context).primary700
|
||||
: Colors.orange,
|
||||
),
|
||||
size: Size.infinite,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ProgressPainter extends CustomPainter {
|
||||
final double progress;
|
||||
final Color color;
|
||||
|
||||
_ProgressPainter({required this.progress, required this.color});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()
|
||||
..color = color
|
||||
..style = PaintingStyle.fill;
|
||||
|
||||
final rect = RRect.fromRectAndRadius(
|
||||
Rect.fromLTWH(0, 0, size.width * progress, size.height),
|
||||
const Radius.circular(2),
|
||||
);
|
||||
|
||||
canvas.drawRRect(rect, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_ProgressPainter oldDelegate) {
|
||||
return oldDelegate.progress != progress || oldDelegate.color != color;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:clipboard/clipboard.dart';
|
||||
@@ -15,24 +14,28 @@ import 'package:ente_auth/services/preference_service.dart';
|
||||
import 'package:ente_auth/store/code_store.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:ente_auth/ui/code_timer_progress.dart';
|
||||
import 'package:ente_auth/ui/components/bottom_action_bar_widget.dart';
|
||||
import 'package:ente_auth/ui/share/code_share.dart';
|
||||
import 'package:ente_auth/ui/utils/icon_utils.dart';
|
||||
import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:ente_auth/utils/platform_util.dart';
|
||||
import 'package:ente_auth/utils/toast_util.dart';
|
||||
import 'package:ente_auth/utils/totp_util.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_context_menu/flutter_context_menu.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:move_to_background/move_to_background.dart';
|
||||
|
||||
class CodeWidget extends StatefulWidget {
|
||||
final Code code;
|
||||
final bool isCompactMode;
|
||||
|
||||
const CodeWidget(
|
||||
this.code, {
|
||||
super.key,
|
||||
required this.isCompactMode,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -49,19 +52,32 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
late bool _shouldShowLargeIcon;
|
||||
late bool _hideCode;
|
||||
bool isMaskingEnabled = false;
|
||||
int _codeTimeStep = -1;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
isMaskingEnabled = PreferenceService.instance.shouldHideCodes();
|
||||
|
||||
_hideCode = isMaskingEnabled;
|
||||
_everySecondTimer =
|
||||
Timer.periodic(const Duration(milliseconds: 500), (Timer t) {
|
||||
String newCode = _getCurrentOTP();
|
||||
if (newCode != _currentCode.value) {
|
||||
_currentCode.value = newCode;
|
||||
if (widget.code.type.isTOTPCompatible) {
|
||||
_nextCode.value = _getNextTotp();
|
||||
int newStep = 0;
|
||||
if (widget.code.type != Type.hotp) {
|
||||
newStep = (((DateTime.now().millisecondsSinceEpoch ~/ 1000).round()) ~/
|
||||
widget.code.period)
|
||||
.floor();
|
||||
} else {
|
||||
newStep = widget.code.counter;
|
||||
}
|
||||
if (_codeTimeStep != newStep) {
|
||||
_codeTimeStep = newStep;
|
||||
String newCode = _getCurrentOTP();
|
||||
if (newCode != _currentCode.value) {
|
||||
_currentCode.value = newCode;
|
||||
if (widget.code.type.isTOTPCompatible) {
|
||||
_nextCode.value = _getNextTotp();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -103,6 +119,18 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
painter: PinBgPainter(
|
||||
color: colorScheme.pinnedBgColor,
|
||||
),
|
||||
size: widget.isCompactMode
|
||||
? const Size(24, 24)
|
||||
: const Size(39, 39),
|
||||
),
|
||||
),
|
||||
if (widget.code.isTrashed && kDebugMode)
|
||||
Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: CustomPaint(
|
||||
painter: PinBgPainter(
|
||||
color: colorScheme.warning700,
|
||||
),
|
||||
size: const Size(39, 39),
|
||||
),
|
||||
),
|
||||
@@ -111,10 +139,12 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
if (widget.code.type.isTOTPCompatible)
|
||||
CodeTimerProgress(
|
||||
period: widget.code.period,
|
||||
CodeTimerProgressCache.getCachedWidget(
|
||||
widget.code.period,
|
||||
),
|
||||
const SizedBox(height: 28),
|
||||
widget.isCompactMode
|
||||
? const SizedBox(height: 4)
|
||||
: const SizedBox(height: 28),
|
||||
Row(
|
||||
children: [
|
||||
_shouldShowLargeIcon ? _getIcon() : const SizedBox.shrink(),
|
||||
@@ -122,22 +152,32 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
child: Column(
|
||||
children: [
|
||||
_getTopRow(),
|
||||
const SizedBox(height: 4),
|
||||
widget.isCompactMode
|
||||
? const SizedBox.shrink()
|
||||
: const SizedBox(height: 4),
|
||||
_getBottomRow(l10n),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
widget.isCompactMode
|
||||
? const SizedBox(height: 4)
|
||||
: const SizedBox(height: 32),
|
||||
],
|
||||
),
|
||||
if (widget.code.isPinned) ...[
|
||||
Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 6, top: 6),
|
||||
child: SvgPicture.asset("assets/svg/pin-card.svg"),
|
||||
padding: widget.isCompactMode
|
||||
? const EdgeInsets.only(right: 4, top: 4)
|
||||
: const EdgeInsets.only(right: 6, top: 6),
|
||||
child: SvgPicture.asset(
|
||||
"assets/svg/pin-card.svg",
|
||||
width: widget.isCompactMode ? 8 : null,
|
||||
height: widget.isCompactMode ? 8 : null,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -174,7 +214,22 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
}
|
||||
: null,
|
||||
onLongPress: () {
|
||||
_copyCurrentOTPToClipboard();
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (_) {
|
||||
return BottomActionBarWidget(
|
||||
code: widget.code,
|
||||
onEdit: () => _onEditPressed(true),
|
||||
onShare: () => _onSharePressed(true),
|
||||
onPin: () => _onPinPressed(true),
|
||||
onTrashed: () => _onTrashPressed(true),
|
||||
onDelete: () => _onDeletePressed(true),
|
||||
onRestore: () => _onRestoreClicked(true),
|
||||
onShowQR: () => _onShowQrPressed(true),
|
||||
onCancel: () => Navigator.of(context).pop(),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: getCardContents(l10n),
|
||||
),
|
||||
@@ -184,36 +239,59 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(left: 16, right: 16, bottom: 8, top: 8),
|
||||
margin: widget.isCompactMode
|
||||
? const EdgeInsets.only(left: 16, right: 16, bottom: 6, top: 6)
|
||||
: const EdgeInsets.only(left: 16, right: 16, bottom: 8, top: 8),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
if (PlatformUtil.isDesktop()) {
|
||||
return ContextMenuRegion(
|
||||
contextMenu: ContextMenu(
|
||||
entries: <ContextMenuEntry>[
|
||||
MenuItem(
|
||||
label: 'QR',
|
||||
icon: Icons.qr_code_2_outlined,
|
||||
onSelected: () => _onShowQrPressed(null),
|
||||
),
|
||||
MenuItem(
|
||||
label: widget.code.isPinned ? l10n.unpinText : l10n.pinText,
|
||||
icon: widget.code.isPinned
|
||||
? Icons.push_pin
|
||||
: Icons.push_pin_outlined,
|
||||
onSelected: () => _onPinPressed(null),
|
||||
),
|
||||
MenuItem(
|
||||
label: l10n.edit,
|
||||
icon: Icons.edit,
|
||||
onSelected: () => _onEditPressed(null),
|
||||
),
|
||||
if (!widget.code.isTrashed &&
|
||||
widget.code.type.isTOTPCompatible)
|
||||
MenuItem(
|
||||
label: context.l10n.share,
|
||||
icon: Icons.adaptive.share_outlined,
|
||||
onSelected: () => _onSharePressed(null),
|
||||
),
|
||||
if (!widget.code.isTrashed)
|
||||
MenuItem(
|
||||
label: 'QR',
|
||||
icon: Icons.qr_code_2_outlined,
|
||||
onSelected: () => _onShowQrPressed(null),
|
||||
),
|
||||
if (!widget.code.isTrashed)
|
||||
MenuItem(
|
||||
label:
|
||||
widget.code.isPinned ? l10n.unpinText : l10n.pinText,
|
||||
icon: widget.code.isPinned
|
||||
? Icons.push_pin
|
||||
: Icons.push_pin_outlined,
|
||||
onSelected: () => _onPinPressed(null),
|
||||
),
|
||||
if (!widget.code.isTrashed)
|
||||
MenuItem(
|
||||
label: l10n.edit,
|
||||
icon: Icons.edit,
|
||||
onSelected: () => _onEditPressed(null),
|
||||
)
|
||||
else
|
||||
MenuItem(
|
||||
label: l10n.restore,
|
||||
icon: Icons.restore_outlined,
|
||||
onSelected: () => _onRestoreClicked(null),
|
||||
),
|
||||
const MenuDivider(),
|
||||
MenuItem(
|
||||
label: l10n.delete,
|
||||
label: widget.code.isTrashed ? l10n.delete : l10n.trash,
|
||||
value: "Delete",
|
||||
icon: Icons.delete,
|
||||
onSelected: () => _onDeletePressed(null),
|
||||
icon: widget.code.isTrashed
|
||||
? Icons.delete_forever
|
||||
: Icons.delete,
|
||||
onSelected: () => widget.code.isTrashed
|
||||
? _onDeletePressed(null)
|
||||
: _onTrashPressed(null),
|
||||
),
|
||||
],
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
@@ -222,95 +300,7 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
return Slidable(
|
||||
key: ValueKey(widget.code.hashCode),
|
||||
endActionPane: ActionPane(
|
||||
extentRatio: 0.90,
|
||||
motion: const ScrollMotion(),
|
||||
children: [
|
||||
const SizedBox(
|
||||
width: 14,
|
||||
),
|
||||
SlidableAction(
|
||||
onPressed: _onShowQrPressed,
|
||||
backgroundColor: Colors.grey.withOpacity(0.1),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
foregroundColor:
|
||||
Theme.of(context).colorScheme.inverseBackgroundColor,
|
||||
icon: Icons.qr_code_2_outlined,
|
||||
label: "QR",
|
||||
padding: const EdgeInsets.only(left: 4, right: 0),
|
||||
spacing: 8,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 14,
|
||||
),
|
||||
CustomSlidableAction(
|
||||
onPressed: _onPinPressed,
|
||||
backgroundColor: Colors.grey.withOpacity(0.1),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
foregroundColor:
|
||||
Theme.of(context).colorScheme.inverseBackgroundColor,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (widget.code.isPinned)
|
||||
SvgPicture.asset(
|
||||
"assets/svg/pin-active.svg",
|
||||
colorFilter: ui.ColorFilter.mode(
|
||||
Theme.of(context).colorScheme.primary,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
)
|
||||
else
|
||||
SvgPicture.asset(
|
||||
"assets/svg/pin-inactive.svg",
|
||||
colorFilter: ui.ColorFilter.mode(
|
||||
Theme.of(context).colorScheme.primary,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
widget.code.isPinned ? l10n.unpinText : l10n.pinText,
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.only(left: 4, right: 0),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 14,
|
||||
),
|
||||
SlidableAction(
|
||||
onPressed: _onEditPressed,
|
||||
backgroundColor: Colors.grey.withOpacity(0.1),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
foregroundColor:
|
||||
Theme.of(context).colorScheme.inverseBackgroundColor,
|
||||
icon: Icons.edit_outlined,
|
||||
label: l10n.edit,
|
||||
padding: const EdgeInsets.only(left: 4, right: 0),
|
||||
spacing: 8,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 14,
|
||||
),
|
||||
SlidableAction(
|
||||
onPressed: _onDeletePressed,
|
||||
backgroundColor: Colors.grey.withOpacity(0.1),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
foregroundColor: colorScheme.deleteCodeTextColor,
|
||||
icon: Icons.delete,
|
||||
label: l10n.delete,
|
||||
padding: const EdgeInsets.only(left: 0, right: 0),
|
||||
spacing: 8,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Builder(
|
||||
builder: (context) => clippedCard(l10n),
|
||||
),
|
||||
);
|
||||
return clippedCard(l10n);
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -331,7 +321,7 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
type: MaterialType.transparency,
|
||||
child: AutoSizeText(
|
||||
_getFormattedCode(value),
|
||||
style: const TextStyle(fontSize: 24),
|
||||
style: TextStyle(fontSize: widget.isCompactMode ? 14 : 24),
|
||||
maxLines: 1,
|
||||
),
|
||||
);
|
||||
@@ -358,8 +348,8 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
type: MaterialType.transparency,
|
||||
child: Text(
|
||||
_getFormattedCode(value),
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
style: TextStyle(
|
||||
fontSize: widget.isCompactMode ? 12 : 18,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
@@ -392,6 +382,7 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
}
|
||||
|
||||
Widget _getTopRow() {
|
||||
bool isCompactMode = widget.isCompactMode;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Row(
|
||||
@@ -403,13 +394,15 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
children: [
|
||||
Text(
|
||||
safeDecode(widget.code.issuer).trim(),
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
style: isCompactMode
|
||||
? Theme.of(context).textTheme.bodyMedium
|
||||
: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
if (!isCompactMode) const SizedBox(height: 2),
|
||||
Text(
|
||||
safeDecode(widget.code.account).trim(),
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
fontSize: 12,
|
||||
fontSize: isCompactMode ? 12 : 12,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
@@ -440,12 +433,14 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
Widget _getIcon() {
|
||||
return Padding(
|
||||
padding: _shouldShowLargeIcon
|
||||
? const EdgeInsets.only(left: 16)
|
||||
? EdgeInsets.only(left: widget.isCompactMode ? 12 : 16)
|
||||
: const EdgeInsets.all(0),
|
||||
child: IconUtils.instance.getIcon(
|
||||
context,
|
||||
safeDecode(widget.code.issuer).trim(),
|
||||
width: _shouldShowLargeIcon ? 42 : 24,
|
||||
width: widget.isCompactMode
|
||||
? (_shouldShowLargeIcon ? 32 : 24)
|
||||
: (_shouldShowLargeIcon ? 42 : 24),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -490,7 +485,10 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onEditPressed(_) async {
|
||||
Future<void> _onEditPressed([bool? pop]) async {
|
||||
if (mounted && pop == true) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
bool isAuthSuccessful = await LocalAuthenticationService.instance
|
||||
.requestLocalAuthentication(context, context.l10n.editCodeAuthMessage);
|
||||
await PlatformUtil.refocusWindows();
|
||||
@@ -511,7 +509,10 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onShowQrPressed(_) async {
|
||||
Future<void> _onShowQrPressed([bool? pop]) async {
|
||||
if (mounted && pop == true) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
bool isAuthSuccessful = await LocalAuthenticationService.instance
|
||||
.requestLocalAuthentication(context, context.l10n.showQRAuthMessage);
|
||||
await PlatformUtil.refocusWindows();
|
||||
@@ -528,7 +529,23 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onPinPressed(_) async {
|
||||
Future<void> _onSharePressed([bool? pop]) async {
|
||||
if (mounted && pop == true) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
bool isAuthSuccessful = await LocalAuthenticationService.instance
|
||||
.requestLocalAuthentication(context, context.l10n.authenticateGeneric);
|
||||
await PlatformUtil.refocusWindows();
|
||||
if (!isAuthSuccessful) {
|
||||
return;
|
||||
}
|
||||
showShareDialog(context, widget.code);
|
||||
}
|
||||
|
||||
Future<void> _onPinPressed([bool? pop]) async {
|
||||
if (mounted && pop == true) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
bool currentlyPinned = widget.code.isPinned;
|
||||
final display = widget.code.display;
|
||||
final Code code = widget.code.copyWith(
|
||||
@@ -546,7 +563,14 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
void _onDeletePressed(_) async {
|
||||
void _onDeletePressed([bool? pop]) async {
|
||||
if (mounted && pop == true) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
if (!widget.code.isTrashed) {
|
||||
showToast(context, 'Code can only be deleted from trash');
|
||||
return;
|
||||
}
|
||||
bool isAuthSuccessful =
|
||||
await LocalAuthenticationService.instance.requestLocalAuthentication(
|
||||
context,
|
||||
@@ -569,6 +593,70 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
void _onTrashPressed([bool? pop]) async {
|
||||
if (mounted && pop == true) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
if (widget.code.isTrashed) {
|
||||
showToast(context, 'Code is already trashed');
|
||||
return;
|
||||
}
|
||||
bool isAuthSuccessful =
|
||||
await LocalAuthenticationService.instance.requestLocalAuthentication(
|
||||
context,
|
||||
context.l10n.deleteCodeAuthMessage,
|
||||
);
|
||||
if (!isAuthSuccessful) {
|
||||
return;
|
||||
}
|
||||
FocusScope.of(context).requestFocus();
|
||||
final l10n = context.l10n;
|
||||
await showChoiceActionSheet(
|
||||
context,
|
||||
title: l10n.trashCode,
|
||||
body: l10n
|
||||
.trashCodeMessage('${widget.code.issuer} (${widget.code.account})'),
|
||||
firstButtonLabel: l10n.trash,
|
||||
isCritical: true,
|
||||
firstButtonOnTap: () async {
|
||||
try {
|
||||
final display = widget.code.display;
|
||||
final Code code = widget.code.copyWith(
|
||||
display: display.copyWith(trashed: true),
|
||||
);
|
||||
await CodeStore.instance.addCode(code);
|
||||
} catch (e) {
|
||||
logger.severe('Failed to trash code: ${e.toString()}');
|
||||
showGenericErrorDialog(context: context, error: e).ignore();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _onRestoreClicked([bool? pop]) async {
|
||||
if (mounted && pop == true) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
if (!widget.code.isTrashed) {
|
||||
showToast(context, 'Code is already restored');
|
||||
return;
|
||||
}
|
||||
FocusScope.of(context).requestFocus();
|
||||
|
||||
try {
|
||||
final display = widget.code.display;
|
||||
final Code code = widget.code.copyWith(
|
||||
display: display.copyWith(trashed: false),
|
||||
);
|
||||
await CodeStore.instance.addCode(code);
|
||||
} catch (e) {
|
||||
logger.severe('Failed to restore code: ${e.toString()}');
|
||||
if (mounted) {
|
||||
showGenericErrorDialog(context: context, error: e).ignore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String _getCurrentOTP() {
|
||||
try {
|
||||
return getOTP(widget.code);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BottomShadowWidget extends StatelessWidget {
|
||||
@@ -15,7 +13,7 @@ class BottomShadowWidget extends StatelessWidget {
|
||||
color: Colors.transparent,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: shadowColor ?? Theme.of(context).colorScheme.background,
|
||||
color: shadowColor ?? Theme.of(context).colorScheme.surface,
|
||||
spreadRadius: 42,
|
||||
blurRadius: 42,
|
||||
offset: Offset(0, offsetDy), // changes position of shadow
|
||||
|
||||
@@ -24,7 +24,7 @@ class DynamicFAB extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
spreadRadius: 200,
|
||||
blurRadius: 100,
|
||||
offset: const Offset(0, 230),
|
||||
|
||||
61
auth/lib/ui/components/actions_bar_widget.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/models/code.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ActionBarWidget extends StatefulWidget {
|
||||
final VoidCallback? onCancel;
|
||||
final Code code;
|
||||
|
||||
const ActionBarWidget({
|
||||
required this.onCancel,
|
||||
required this.code,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ActionBarWidget> createState() => _ActionBarWidgetState();
|
||||
}
|
||||
|
||||
class _ActionBarWidgetState extends State<ActionBarWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final textTheme = getEnteTextTheme(context);
|
||||
return SizedBox(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 8, 20, 8),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
widget.code.issuer,
|
||||
style: textTheme.miniMuted,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () {
|
||||
widget.onCancel?.call();
|
||||
},
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Text(
|
||||
context.l10n.cancel,
|
||||
style: textTheme.mini,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
81
auth/lib/ui/components/bottom_action_bar_widget.dart
Normal file
@@ -0,0 +1,81 @@
|
||||
import 'package:ente_auth/models/code.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:ente_auth/ui/components/actions_bar_widget.dart';
|
||||
import 'package:ente_auth/ui/components/code_selection_actions_widget.dart';
|
||||
import 'package:ente_auth/ui/components/components_constants.dart';
|
||||
import "package:ente_auth/ui/components/divider_widget.dart";
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BottomActionBarWidget extends StatelessWidget {
|
||||
final Code code;
|
||||
final VoidCallback? onCancel;
|
||||
final Color? backgroundColor;
|
||||
final VoidCallback? onShare;
|
||||
final VoidCallback? onPin;
|
||||
final VoidCallback? onShowQR;
|
||||
final VoidCallback? onEdit;
|
||||
final VoidCallback? onRestore;
|
||||
final VoidCallback? onDelete;
|
||||
final VoidCallback? onTrashed;
|
||||
|
||||
const BottomActionBarWidget({
|
||||
required this.code,
|
||||
this.onCancel,
|
||||
this.backgroundColor,
|
||||
super.key,
|
||||
this.onShare,
|
||||
this.onPin,
|
||||
this.onShowQR,
|
||||
this.onEdit,
|
||||
this.onRestore,
|
||||
this.onDelete,
|
||||
this.onTrashed,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bottomPadding = MediaQuery.of(context).padding.bottom;
|
||||
final widthOfScreen = MediaQuery.of(context).size.width;
|
||||
final colorScheme = getEnteColorScheme(context);
|
||||
final double leftRightPadding = widthOfScreen > restrictedMaxWidth
|
||||
? (widthOfScreen - restrictedMaxWidth) / 2
|
||||
: 0;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor ?? colorScheme.backgroundElevated2,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(8),
|
||||
topRight: Radius.circular(8),
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.only(
|
||||
top: 4,
|
||||
bottom: bottomPadding,
|
||||
right: leftRightPadding,
|
||||
left: leftRightPadding,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
CodeSelectionActionsWidget(
|
||||
code: code,
|
||||
onShare: onShare,
|
||||
onPin: onPin,
|
||||
onShowQR: onShowQR,
|
||||
onEdit: onEdit,
|
||||
onRestore: onRestore,
|
||||
onDelete: onDelete,
|
||||
onTrashed: onTrashed,
|
||||
),
|
||||
const DividerWidget(dividerType: DividerType.bottomBar),
|
||||
ActionBarWidget(
|
||||
code: code,
|
||||
onCancel: onCancel,
|
||||
),
|
||||
// const SizedBox(height: 2)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
138
auth/lib/ui/components/code_selection_actions_widget.dart
Normal file
@@ -0,0 +1,138 @@
|
||||
import "package:ente_auth/l10n/l10n.dart";
|
||||
import "package:ente_auth/models/code.dart";
|
||||
import "package:ente_auth/ui/components/selection_action_button.dart";
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CodeSelectionActionsWidget extends StatefulWidget {
|
||||
final Code code;
|
||||
final VoidCallback? onShare;
|
||||
final VoidCallback? onPin;
|
||||
final VoidCallback? onShowQR;
|
||||
final VoidCallback? onEdit;
|
||||
final VoidCallback? onRestore;
|
||||
final VoidCallback? onDelete;
|
||||
final VoidCallback? onTrashed;
|
||||
|
||||
const CodeSelectionActionsWidget({
|
||||
super.key,
|
||||
required this.code,
|
||||
this.onShare,
|
||||
this.onPin,
|
||||
this.onShowQR,
|
||||
this.onEdit,
|
||||
this.onRestore,
|
||||
this.onDelete,
|
||||
this.onTrashed,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CodeSelectionActionsWidget> createState() =>
|
||||
_CodeSelectionActionsWidgetState();
|
||||
}
|
||||
|
||||
class _CodeSelectionActionsWidgetState
|
||||
extends State<CodeSelectionActionsWidget> {
|
||||
late final scrollController = ScrollController();
|
||||
|
||||
// static final _logger = Logger("CodeSelectionActionsWidget");
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<SelectionActionButton> items = [];
|
||||
|
||||
if (!widget.code.isTrashed) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
labelText: context.l10n.share,
|
||||
icon: Icons.adaptive.share_outlined,
|
||||
onTap: widget.onShare,
|
||||
),
|
||||
);
|
||||
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
labelText: widget.code.isPinned
|
||||
? context.l10n.unpinText
|
||||
: context.l10n.pinText,
|
||||
icon: widget.code.isPinned ? Icons.push_pin : Icons.push_pin_outlined,
|
||||
onTap: widget.onPin,
|
||||
),
|
||||
);
|
||||
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
labelText: 'QR',
|
||||
icon: Icons.qr_code_2_outlined,
|
||||
onTap: widget.onShowQR,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.code.isTrashed) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
labelText: context.l10n.restore,
|
||||
icon: Icons.restore_outlined,
|
||||
onTap: widget.onRestore,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
labelText: context.l10n.edit,
|
||||
icon: Icons.edit,
|
||||
onTap: widget.onEdit,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
labelText:
|
||||
widget.code.isTrashed ? context.l10n.delete : context.l10n.trash,
|
||||
icon: widget.code.isTrashed ? Icons.delete_forever : Icons.delete,
|
||||
onTap: widget.code.isTrashed ? widget.onDelete : widget.onTrashed,
|
||||
),
|
||||
);
|
||||
|
||||
if (items.isNotEmpty) {
|
||||
// h4ck: https://github.com/flutter/flutter/issues/57920#issuecomment-893970066
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).removePadding(removeBottom: true),
|
||||
child: SafeArea(
|
||||
child: Scrollbar(
|
||||
radius: const Radius.circular(1),
|
||||
thickness: 2,
|
||||
controller: scrollController,
|
||||
thumbVisibility: true,
|
||||
child: SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
physics: const BouncingScrollPhysics(
|
||||
decelerationRate: ScrollDecelerationRate.fast,
|
||||
),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(bottom: 24),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(width: 4),
|
||||
...items,
|
||||
const SizedBox(width: 4),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return const SizedBox();
|
||||
}
|
||||
}
|
||||
196
auth/lib/ui/components/selection_action_button.dart
Normal file
@@ -0,0 +1,196 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import "package:ente_auth/theme/ente_theme.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_svg/svg.dart";
|
||||
|
||||
/// Pass icon or asset path of svg
|
||||
class SelectionActionButton extends StatelessWidget {
|
||||
final String labelText;
|
||||
final IconData? icon;
|
||||
final String? svgAssetPath;
|
||||
final VoidCallback? onTap;
|
||||
final bool shouldShow;
|
||||
|
||||
const SelectionActionButton({
|
||||
required this.labelText,
|
||||
required this.onTap,
|
||||
this.icon,
|
||||
this.svgAssetPath,
|
||||
this.shouldShow = true,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(icon != null || svgAssetPath != null);
|
||||
return AnimatedSize(
|
||||
duration: const Duration(milliseconds: 350),
|
||||
curve: Curves.easeInOutCirc,
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: shouldShow
|
||||
? _Body(
|
||||
labelText: labelText,
|
||||
icon: icon,
|
||||
onTap: onTap,
|
||||
svgAssetPath: svgAssetPath,
|
||||
)
|
||||
: const SizedBox(
|
||||
height: 60,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
final String labelText;
|
||||
final IconData? icon;
|
||||
final String? svgAssetPath;
|
||||
final VoidCallback? onTap;
|
||||
const _Body({
|
||||
required this.labelText,
|
||||
required this.onTap,
|
||||
this.icon,
|
||||
this.svgAssetPath,
|
||||
});
|
||||
|
||||
@override
|
||||
State<_Body> createState() => __BodyState();
|
||||
}
|
||||
|
||||
class __BodyState extends State<_Body> {
|
||||
static const minWidth = 64.0;
|
||||
late double widthOfButton;
|
||||
Color? backgroundColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
widthOfButton = getWidthOfButton();
|
||||
final colorScheme = getEnteColorScheme(context);
|
||||
return GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
onTapDown: (details) {
|
||||
setState(() {
|
||||
backgroundColor = colorScheme.fillFaintPressed;
|
||||
});
|
||||
},
|
||||
onTapUp: (details) {
|
||||
setState(() {
|
||||
backgroundColor = null;
|
||||
});
|
||||
},
|
||||
onTapCancel: () {
|
||||
setState(() {
|
||||
backgroundColor = null;
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: backgroundColor,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
|
||||
child: SizedBox(
|
||||
width: widthOfButton,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (widget.icon == Icons.navigation_rounded)
|
||||
Transform.rotate(
|
||||
angle: math.pi / 2,
|
||||
child: Icon(
|
||||
widget.icon,
|
||||
size: 24,
|
||||
color: getEnteColorScheme(context).primary300,
|
||||
shadows: const [
|
||||
BoxShadow(
|
||||
color: Color.fromARGB(12, 0, 179, 60),
|
||||
offset: Offset(0, 2.51),
|
||||
blurRadius: 5.02,
|
||||
spreadRadius: 0,
|
||||
),
|
||||
BoxShadow(
|
||||
color: Color.fromARGB(24, 0, 179, 60),
|
||||
offset: Offset(0, 1.25),
|
||||
blurRadius: 3.76,
|
||||
spreadRadius: 0,
|
||||
),
|
||||
BoxShadow(
|
||||
color: Color.fromARGB(24, 0, 179, 60),
|
||||
offset: Offset(0, 0.63),
|
||||
blurRadius: 1.88,
|
||||
spreadRadius: 0,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
else
|
||||
widget.svgAssetPath != null
|
||||
? SvgPicture.asset(
|
||||
widget.svgAssetPath!,
|
||||
colorFilter: ColorFilter.mode(
|
||||
getEnteColorScheme(context).textMuted,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
width: 24,
|
||||
height: 24,
|
||||
)
|
||||
: Icon(
|
||||
widget.icon,
|
||||
size: 24,
|
||||
color: getEnteColorScheme(context).textMuted,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
widget.labelText,
|
||||
textAlign: TextAlign.center,
|
||||
//textTheme in [getWidthOfLongestWord] should be same as this
|
||||
style: getEnteTextTheme(context).miniMuted,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
getWidthOfButton() {
|
||||
final widthOfWidestWord = getWidthOfWidestWord(
|
||||
widget.labelText,
|
||||
);
|
||||
if (widthOfWidestWord > minWidth) return widthOfWidestWord;
|
||||
return minWidth;
|
||||
}
|
||||
|
||||
double getWidthOfWidestWord(String labelText) {
|
||||
final words = labelText.split(RegExp(r'\s+'));
|
||||
if (words.isEmpty) return 0.0;
|
||||
|
||||
double maxWidth = 0.0;
|
||||
for (String word in words) {
|
||||
final width =
|
||||
computeWidthOfWord(word, getEnteTextTheme(context).miniMuted);
|
||||
if (width > maxWidth) {
|
||||
maxWidth = width;
|
||||
}
|
||||
}
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
//Todo: this doesn't give the correct width of the word, make it right
|
||||
double computeWidthOfWord(String text, TextStyle style) {
|
||||
final textPainter = TextPainter(
|
||||
text: TextSpan(text: text, style: style),
|
||||
maxLines: 1,
|
||||
textDirection: TextDirection.ltr,
|
||||
textScaler: MediaQuery.textScalerOf(context),
|
||||
)..layout();
|
||||
//buffer of 8 added as width is shorter than actual text width
|
||||
return textPainter.size.width + 8;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import 'package:ente_auth/core/event_bus.dart';
|
||||
import 'package:ente_auth/events/codes_updated_event.dart';
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/services/preference_service.dart';
|
||||
import 'package:ente_auth/utils/platform_util.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CoachMarkWidget extends StatelessWidget {
|
||||
@@ -22,7 +24,7 @@ class CoachMarkWidget extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
color: Theme.of(context).colorScheme.background.withOpacity(0.1),
|
||||
color: Theme.of(context).colorScheme.surface.withOpacity(0.1),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
|
||||
child: Row(
|
||||
@@ -33,14 +35,16 @@ class CoachMarkWidget extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.swipe_left,
|
||||
Icons.info_outline,
|
||||
size: 42,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Text(
|
||||
l10n.swipeHint,
|
||||
PlatformUtil.isDesktop()
|
||||
? l10n.hintForDesktop
|
||||
: l10n.hintForMobile,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const SizedBox(
|
||||
|
||||
@@ -75,7 +75,7 @@ class HomeEmptyStateWidget extends StatelessWidget {
|
||||
onTap: () {
|
||||
showModalBottomSheet<void>(
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.background,
|
||||
Theme.of(context).colorScheme.surface,
|
||||
barrierColor: Colors.black87,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
|
||||
@@ -22,11 +22,15 @@ import 'package:ente_auth/ui/account/logout_dialog.dart';
|
||||
import 'package:ente_auth/ui/code_error_widget.dart';
|
||||
import 'package:ente_auth/ui/code_widget.dart';
|
||||
import 'package:ente_auth/ui/common/loading_widget.dart';
|
||||
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
|
||||
import 'package:ente_auth/ui/components/dialog_widget.dart';
|
||||
import 'package:ente_auth/ui/components/models/button_type.dart';
|
||||
import 'package:ente_auth/ui/home/coach_mark_widget.dart';
|
||||
import 'package:ente_auth/ui/home/home_empty_state.dart';
|
||||
import 'package:ente_auth/ui/home/speed_dial_label_widget.dart';
|
||||
import 'package:ente_auth/ui/scanner_page.dart';
|
||||
import 'package:ente_auth/ui/settings_page.dart';
|
||||
import 'package:ente_auth/ui/tools/app_lock.dart';
|
||||
import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:ente_auth/utils/platform_util.dart';
|
||||
import 'package:ente_auth/utils/totp_util.dart';
|
||||
@@ -55,6 +59,9 @@ class _HomePageState extends State<HomePage> {
|
||||
final Logger _logger = Logger("HomePage");
|
||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
// Used to request focus on the search box when clicked the search icon
|
||||
late FocusNode searchBoxFocusNode;
|
||||
|
||||
final TextEditingController _textController = TextEditingController();
|
||||
final bool _autoFocusSearch =
|
||||
PreferenceService.instance.shouldAutoFocusOnSearchBar();
|
||||
@@ -67,6 +74,10 @@ class _HomePageState extends State<HomePage> {
|
||||
StreamSubscription<TriggerLogoutEvent>? _triggerLogoutEvent;
|
||||
StreamSubscription<IconsChangedEvent>? _iconsChangedEvent;
|
||||
String selectedTag = "";
|
||||
bool _isTrashOpen = false;
|
||||
bool hasTrashedCodes = false;
|
||||
bool hasNonTrashedCodes = false;
|
||||
bool isCompactMode = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -89,15 +100,34 @@ class _HomePageState extends State<HomePage> {
|
||||
setState(() {});
|
||||
});
|
||||
_showSearchBox = _autoFocusSearch;
|
||||
|
||||
searchBoxFocusNode = FocusNode();
|
||||
}
|
||||
|
||||
void _loadCodes() {
|
||||
CodeStore.instance.getAllCodes().then((codes) {
|
||||
_allCodes = codes;
|
||||
hasTrashedCodes = false;
|
||||
hasNonTrashedCodes = false;
|
||||
for (final c in _allCodes ?? []) {
|
||||
if (c.isTrashed) {
|
||||
hasTrashedCodes = true;
|
||||
} else {
|
||||
hasNonTrashedCodes = true;
|
||||
}
|
||||
if (hasNonTrashedCodes && hasTrashedCodes) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasTrashedCodes) {
|
||||
_isTrashOpen = false;
|
||||
}
|
||||
if (!hasNonTrashedCodes && hasTrashedCodes) {
|
||||
_isTrashOpen = true;
|
||||
}
|
||||
|
||||
CodeDisplayStore.instance.getAllTags(allCodes: _allCodes).then((value) {
|
||||
tags = value;
|
||||
|
||||
if (mounted) {
|
||||
if (!tags.contains(selectedTag)) {
|
||||
selectedTag = "";
|
||||
@@ -124,7 +154,8 @@ class _HomePageState extends State<HomePage> {
|
||||
for (final Code codeState in _allCodes!) {
|
||||
if (codeState.hasError ||
|
||||
selectedTag != "" &&
|
||||
!codeState.display.tags.contains(selectedTag)) {
|
||||
!codeState.display.tags.contains(selectedTag) ||
|
||||
(codeState.isTrashed != _isTrashOpen)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -136,11 +167,19 @@ class _HomePageState extends State<HomePage> {
|
||||
}
|
||||
_filteredCodes = issuerMatch;
|
||||
_filteredCodes.addAll(accountMatch);
|
||||
} else if (_isTrashOpen) {
|
||||
_filteredCodes = _allCodes
|
||||
?.where(
|
||||
(element) => !element.hasError && element.isTrashed,
|
||||
)
|
||||
.toList() ??
|
||||
[];
|
||||
} else {
|
||||
_filteredCodes = _allCodes
|
||||
?.where(
|
||||
(element) =>
|
||||
!element.hasError &&
|
||||
!element.isTrashed &&
|
||||
(selectedTag == "" ||
|
||||
element.display.tags.contains(selectedTag)),
|
||||
)
|
||||
@@ -158,6 +197,9 @@ class _HomePageState extends State<HomePage> {
|
||||
_triggerLogoutEvent?.cancel();
|
||||
_iconsChangedEvent?.cancel();
|
||||
_textController.removeListener(_applyFilteringAndRefresh);
|
||||
|
||||
searchBoxFocusNode.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -191,12 +233,35 @@ class _HomePageState extends State<HomePage> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> navigateToLockScreen() async {
|
||||
final bool shouldShowLockScreen =
|
||||
await Configuration.instance.shouldShowLockScreen();
|
||||
if (shouldShowLockScreen) {
|
||||
await AppLock.of(context)!.showLockScreen();
|
||||
} else {
|
||||
await showDialogWidget(
|
||||
context: context,
|
||||
title: context.l10n.appLockNotEnabled,
|
||||
body: context.l10n.appLockNotEnabledDescription,
|
||||
isDismissible: true,
|
||||
buttons: const [
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.secondary,
|
||||
labelText: "OK",
|
||||
isInAlert: true,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
isCompactMode = PreferenceService.instance.isCompactMode();
|
||||
|
||||
return PopScope(
|
||||
onPopInvoked: (_) async {
|
||||
onPopInvokedWithResult: (_, result) async {
|
||||
if (_isSettingsOpen) {
|
||||
scaffoldKey.currentState!.closeDrawer();
|
||||
return;
|
||||
@@ -241,9 +306,22 @@ class _HomePageState extends State<HomePage> {
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
),
|
||||
focusNode: searchBoxFocusNode,
|
||||
),
|
||||
centerTitle: true,
|
||||
centerTitle: PlatformUtil.isDesktop() ? false : true,
|
||||
actions: <Widget>[
|
||||
PlatformUtil.isDesktop()
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.lock),
|
||||
tooltip: l10n.appLock,
|
||||
onPressed: () async {
|
||||
await navigateToLockScreen();
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
const SizedBox(
|
||||
width: 4,
|
||||
),
|
||||
IconButton(
|
||||
icon: _showSearchBox
|
||||
? const Icon(Icons.clear)
|
||||
@@ -258,6 +336,12 @@ class _HomePageState extends State<HomePage> {
|
||||
_searchText = "";
|
||||
} else {
|
||||
_searchText = _textController.text;
|
||||
|
||||
// Request focus on the search box
|
||||
// For Windows only for now. "Platform.isWindows" can be removed if other platforms has been tested.
|
||||
if (Platform.isWindows) {
|
||||
searchBoxFocusNode.requestFocus();
|
||||
}
|
||||
}
|
||||
_applyFilteringAndRefresh();
|
||||
},
|
||||
@@ -287,6 +371,8 @@ class _HomePageState extends State<HomePage> {
|
||||
final anyCodeHasError =
|
||||
_allCodes?.firstWhereOrNull((element) => element.hasError) != null;
|
||||
final indexOffset = anyCodeHasError ? 1 : 0;
|
||||
final itemCount = (hasNonTrashedCodes ? tags.length + 1 : 0) +
|
||||
(hasTrashedCodes ? 1 : 0);
|
||||
|
||||
final list = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -300,21 +386,37 @@ class _HomePageState extends State<HomePage> {
|
||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 2),
|
||||
separatorBuilder: (context, index) =>
|
||||
const SizedBox(width: 8),
|
||||
itemCount: tags.length + 1,
|
||||
itemCount: itemCount,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == 0) {
|
||||
if (index == 0 && hasNonTrashedCodes) {
|
||||
return TagChip(
|
||||
label: "All",
|
||||
state: selectedTag == ""
|
||||
label: l10n.all,
|
||||
state: selectedTag == "" && _isTrashOpen == false
|
||||
? TagChipState.selected
|
||||
: TagChipState.unselected,
|
||||
onTap: () {
|
||||
selectedTag = "";
|
||||
_isTrashOpen = false;
|
||||
setState(() {});
|
||||
_applyFilteringAndRefresh();
|
||||
},
|
||||
);
|
||||
}
|
||||
if (index == itemCount - 1 && hasTrashedCodes) {
|
||||
return TagChip(
|
||||
label: l10n.trash,
|
||||
state: _isTrashOpen
|
||||
? TagChipState.selected
|
||||
: TagChipState.unselected,
|
||||
onTap: () {
|
||||
selectedTag = "";
|
||||
_isTrashOpen = !_isTrashOpen;
|
||||
setState(() {});
|
||||
_applyFilteringAndRefresh();
|
||||
},
|
||||
iconData: Icons.delete,
|
||||
);
|
||||
}
|
||||
return TagChip(
|
||||
label: tags[index - 1],
|
||||
action: TagChipAction.menu,
|
||||
@@ -322,6 +424,7 @@ class _HomePageState extends State<HomePage> {
|
||||
? TagChipState.selected
|
||||
: TagChipState.unselected,
|
||||
onTap: () {
|
||||
_isTrashOpen = false;
|
||||
if (selectedTag == tags[index - 1]) {
|
||||
selectedTag = "";
|
||||
setState(() {});
|
||||
@@ -354,9 +457,13 @@ class _HomePageState extends State<HomePage> {
|
||||
}
|
||||
final newIndex = index - indexOffset;
|
||||
|
||||
final code = _filteredCodes[newIndex];
|
||||
|
||||
return ClipRect(
|
||||
child: CodeWidget(
|
||||
_filteredCodes[newIndex],
|
||||
key: ValueKey(code.hashCode),
|
||||
code,
|
||||
isCompactMode: isCompactMode,
|
||||
),
|
||||
);
|
||||
}),
|
||||
@@ -387,6 +494,7 @@ class _HomePageState extends State<HomePage> {
|
||||
final codeState = _filteredCodes[index];
|
||||
return CodeWidget(
|
||||
codeState,
|
||||
isCompactMode: isCompactMode,
|
||||
);
|
||||
}),
|
||||
itemCount: _filteredCodes.length,
|
||||
@@ -484,7 +592,7 @@ class _HomePageState extends State<HomePage> {
|
||||
foregroundColor: Theme.of(context).colorScheme.fabForegroundColor,
|
||||
backgroundColor: Theme.of(context).colorScheme.fabBackgroundColor,
|
||||
overlayOpacity: 0.5,
|
||||
overlayColor: Theme.of(context).colorScheme.background,
|
||||
overlayColor: Theme.of(context).colorScheme.surface,
|
||||
elevation: 8.0,
|
||||
animationCurve: Curves.elasticInOut,
|
||||
children: [
|
||||
|
||||
@@ -62,8 +62,8 @@ class _AppUpdateDialogState extends State<AppUpdateDialog> {
|
||||
height: 64,
|
||||
child: OutlinedButton(
|
||||
style: Theme.of(context).outlinedButtonTheme.style!.copyWith(
|
||||
textStyle: MaterialStateProperty.resolveWith<TextStyle?>(
|
||||
(Set<MaterialState> states) {
|
||||
textStyle: WidgetStateProperty.resolveWith<TextStyle?>(
|
||||
(Set<WidgetState> states) {
|
||||
return Theme.of(context).textTheme.titleMedium;
|
||||
},
|
||||
),
|
||||
|
||||
@@ -129,8 +129,10 @@ Future<int?> _processAegisExportFile(
|
||||
}
|
||||
final Map<String, String> groupIDToName = {};
|
||||
try {
|
||||
for (var item in aegisDB?['groups']) {
|
||||
groupIDToName[item['uuid']] = item['name'];
|
||||
if (aegisDB?['groups'] != null) {
|
||||
for (var item in aegisDB?['groups']) {
|
||||
groupIDToName[item['uuid']] = item['name'];
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
Logger("AegisImport").warning("Failed to parse groups", e);
|
||||
@@ -149,9 +151,11 @@ Future<int?> _processAegisExportFile(
|
||||
var digits = item['info']['digits'];
|
||||
|
||||
var counter = item['info']['counter'];
|
||||
for (var group in item['groups']) {
|
||||
if (groupIDToName.containsKey(group)) {
|
||||
tags.add(groupIDToName[group]!);
|
||||
if (item['groups'] != null) {
|
||||
for (var group in item['groups']) {
|
||||
if (groupIDToName.containsKey(group)) {
|
||||
tags.add(groupIDToName[group]!);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Build the OTP URL
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:ente_auth/app/view/app.dart';
|
||||
import 'package:ente_auth/core/event_bus.dart';
|
||||
import 'package:ente_auth/core/logging/super_logging.dart';
|
||||
import 'package:ente_auth/events/icons_changed_event.dart';
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/locale.dart';
|
||||
import 'package:ente_auth/services/preference_service.dart';
|
||||
@@ -78,6 +80,22 @@ class _AdvancedSectionWidgetState extends State<AdvancedSectionWidget> {
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: l10n.compactMode,
|
||||
),
|
||||
trailingWidget: ToggleSwitchWidget(
|
||||
value: () => PreferenceService.instance.isCompactMode(),
|
||||
onChanged: () async {
|
||||
await PreferenceService.instance.setCompactMode(
|
||||
!PreferenceService.instance.isCompactMode(),
|
||||
);
|
||||
Bus.instance.fire(IconsChangedEvent());
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: l10n.shouldHideCode,
|
||||
@@ -88,7 +106,7 @@ class _AdvancedSectionWidgetState extends State<AdvancedSectionWidget> {
|
||||
await PreferenceService.instance.setHideCodes(
|
||||
!PreferenceService.instance.shouldHideCodes(),
|
||||
);
|
||||
if(PreferenceService.instance.shouldHideCodes()) {
|
||||
if (PreferenceService.instance.shouldHideCodes()) {
|
||||
showToast(context, context.l10n.doubleTapToViewHiddenCode);
|
||||
}
|
||||
setState(() {});
|
||||
|
||||
@@ -5,9 +5,12 @@ import "package:ente_auth/core/configuration.dart";
|
||||
import "package:ente_auth/l10n/l10n.dart";
|
||||
import "package:ente_auth/services/local_authentication_service.dart";
|
||||
import "package:ente_auth/theme/ente_theme.dart";
|
||||
import "package:ente_auth/ui/components/buttons/button_widget.dart";
|
||||
import "package:ente_auth/ui/components/captioned_text_widget.dart";
|
||||
import "package:ente_auth/ui/components/dialog_widget.dart";
|
||||
import "package:ente_auth/ui/components/divider_widget.dart";
|
||||
import "package:ente_auth/ui/components/menu_item_widget.dart";
|
||||
import "package:ente_auth/ui/components/models/button_type.dart";
|
||||
import "package:ente_auth/ui/components/title_bar_title_widget.dart";
|
||||
import "package:ente_auth/ui/components/title_bar_widget.dart";
|
||||
import "package:ente_auth/ui/components/toggle_switch_widget.dart";
|
||||
@@ -15,7 +18,6 @@ import "package:ente_auth/ui/settings/lock_screen/lock_screen_auto_lock.dart";
|
||||
import "package:ente_auth/ui/settings/lock_screen/lock_screen_password.dart";
|
||||
import "package:ente_auth/ui/settings/lock_screen/lock_screen_pin.dart";
|
||||
import "package:ente_auth/ui/tools/app_lock.dart";
|
||||
import "package:ente_auth/utils/dialog_util.dart";
|
||||
import "package:ente_auth/utils/lock_screen_settings.dart";
|
||||
import "package:ente_auth/utils/navigation_util.dart";
|
||||
import "package:ente_auth/utils/platform_util.dart";
|
||||
@@ -67,10 +69,18 @@ class _LockScreenOptionsState extends State<LockScreenOptions> {
|
||||
await _lockscreenSetting.removePinAndPassword();
|
||||
await _configuration.setSystemLockScreen(!isSystemLockEnabled);
|
||||
} else {
|
||||
await showErrorDialog(
|
||||
context,
|
||||
context.l10n.noSystemLockFound,
|
||||
context.l10n.deviceLockEnablePreSteps,
|
||||
await showDialogWidget(
|
||||
context: context,
|
||||
title: context.l10n.noSystemLockFound,
|
||||
body: context.l10n.deviceLockEnablePreSteps,
|
||||
isDismissible: true,
|
||||
buttons: const [
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.secondary,
|
||||
labelText: "OK",
|
||||
isInAlert: true,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
await _initializeSettings();
|
||||
|
||||
@@ -44,7 +44,7 @@ class _SupportSectionWidgetState extends State<SupportSectionWidget> {
|
||||
onTap: () async {
|
||||
// ignore: unawaited_futures
|
||||
showModalBottomSheet<void>(
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
barrierColor: Colors.black87,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
|
||||
154
auth/lib/ui/share/code_share.dart
Normal file
@@ -0,0 +1,154 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/models/code.dart';
|
||||
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
|
||||
import 'package:ente_auth/ui/components/models/button_type.dart';
|
||||
import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:ente_auth/utils/share_utils.dart';
|
||||
import 'package:ente_auth/utils/totp_util.dart';
|
||||
import 'package:ente_crypto_dart/ente_crypto_dart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
class ShareCodeDialog extends StatefulWidget {
|
||||
final Code code;
|
||||
const ShareCodeDialog({super.key, required this.code});
|
||||
|
||||
@override
|
||||
State<ShareCodeDialog> createState() => _ShareCodeDialogState();
|
||||
}
|
||||
|
||||
class _ShareCodeDialogState extends State<ShareCodeDialog> {
|
||||
final Logger logger = Logger('_ShareCodeDialogState');
|
||||
final List<int> _durationInMins = [2, 5, 10];
|
||||
late int selectedValue;
|
||||
|
||||
String getItemLabel(int min) {
|
||||
if (min == 60) return '1 hour';
|
||||
if (min > 60) {
|
||||
var hour = '${min ~/ 60}';
|
||||
if (min % 60 == 0) return '$hour hour';
|
||||
var minx = '${min % 60}';
|
||||
return '$hour hr $minx min';
|
||||
}
|
||||
return '$min min';
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
selectedValue = _durationInMins[1];
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(context.l10n.shareCodes),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(context.l10n.shareCodesDuration),
|
||||
const SizedBox(height: 10),
|
||||
DropdownButtonHideUnderline(
|
||||
child: DropdownButton2(
|
||||
hint: const Text('Select an option'),
|
||||
items: _durationInMins
|
||||
.map(
|
||||
(item) => DropdownMenuItem<int>(
|
||||
value: item,
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(getItemLabel(item)),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
value: selectedValue,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedValue = value ?? 2;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.primary,
|
||||
buttonSize: ButtonSize.large,
|
||||
labelText: context.l10n.share,
|
||||
onTap: () async {
|
||||
try {
|
||||
await shareCode(selectedValue);
|
||||
Navigator.of(context).pop();
|
||||
} catch (e, s) {
|
||||
logger.severe('Failed to generate shared codes', e, s);
|
||||
showGenericErrorDialog(context: context, error: e).ignore();
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.secondary,
|
||||
buttonSize: ButtonSize.large,
|
||||
labelText: context.l10n.cancel,
|
||||
onTap: () async {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> shareCode(int durationInMin) async {
|
||||
final int count = ((durationInMin * 60.0) / widget.code.period).ceil();
|
||||
final result = generateFutureTotpCodes(widget.code, count);
|
||||
Map<String, dynamic> data = {
|
||||
'startTime': result.$1,
|
||||
'step': widget.code.period,
|
||||
'codes': result.$2.join(","),
|
||||
};
|
||||
final Uint8List key = _generate256BitKey();
|
||||
Uint8List input = utf8.encode(jsonEncode(data));
|
||||
final encResult = await CryptoUtil.encryptData(input, key);
|
||||
String url =
|
||||
'https://auth.ente.io/share?data=${_uint8ListToUrlSafeBase64(encResult.encryptedData!)}&header=${_uint8ListToUrlSafeBase64(encResult.header!)}#${_uint8ListToUrlSafeBase64(key)}';
|
||||
try {
|
||||
await shareText(url, context: context);
|
||||
} catch (e) {
|
||||
logger.warning('Failed to share code: ${e.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
String _uint8ListToUrlSafeBase64(Uint8List data) {
|
||||
String base64Str = base64UrlEncode(data);
|
||||
return base64Str.replaceAll('=', '');
|
||||
}
|
||||
|
||||
Uint8List _generate256BitKey() {
|
||||
final random = Random.secure();
|
||||
final bytes = Uint8List(32); // 32 bytes = 32 * 8 bits = 256 bits
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = random
|
||||
.nextInt(256); // Generates a random number between 0 and 255 (1 byte)
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
void showShareDialog(BuildContext context, Code code) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return ShareCodeDialog(
|
||||
code: code,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -67,13 +67,13 @@ class _AppLockState extends State<AppLock> with WidgetsBindingObserver {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
|
||||
this._didUnlockForAppLaunch = !this.widget.enabled;
|
||||
this._isLocked = false;
|
||||
this._enabled = this.widget.enabled;
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -40,10 +40,6 @@ class _LockScreenState extends State<LockScreen> with WidgetsBindingObserver {
|
||||
invalidAttemptCount = _lockscreenSetting.getInvalidAttemptCount();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
if (isNonMobileIOSDevice()) {
|
||||
_logger.info('ignore init for non mobile iOS device');
|
||||
return;
|
||||
}
|
||||
_showLockScreen(source: "postFrameInit");
|
||||
});
|
||||
_platformBrightness =
|
||||
@@ -190,14 +186,6 @@ class _LockScreenState extends State<LockScreen> with WidgetsBindingObserver {
|
||||
);
|
||||
}
|
||||
|
||||
bool isNonMobileIOSDevice() {
|
||||
if (Platform.isAndroid) {
|
||||
return false;
|
||||
}
|
||||
var shortestSide = MediaQuery.of(context).size.shortestSide;
|
||||
return shortestSide > 600 ? true : false;
|
||||
}
|
||||
|
||||
void _onLogoutTapped(BuildContext context) {
|
||||
showChoiceActionSheet(
|
||||
context,
|
||||
@@ -206,6 +194,8 @@ class _LockScreenState extends State<LockScreen> with WidgetsBindingObserver {
|
||||
isCritical: true,
|
||||
firstButtonOnTap: () async {
|
||||
await UserService.instance.logout(context);
|
||||
// To start the app afresh, resetting all state.
|
||||
Process.killPid(pid, ProcessSignal.sigkill);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -109,14 +109,14 @@ String parseErrorForUI(
|
||||
final DioException dioError = error;
|
||||
if (dioError.type == DioExceptionType.badResponse) {
|
||||
if (dioError.response?.data["code"] != null) {
|
||||
errorInfo = "Reason: " + dioError.response!.data["code"];
|
||||
errorInfo = "Reason: ${dioError.response!.data["code"]}";
|
||||
} else {
|
||||
errorInfo = "Reason: " + dioError.response!.data.toString();
|
||||
errorInfo = "Reason: ${dioError.response!.data}";
|
||||
}
|
||||
} else if (dioError.type == DioExceptionType.unknown) {
|
||||
errorInfo = "Reason: " + dioError.error.toString();
|
||||
errorInfo = "Reason: $dioError.error";
|
||||
} else {
|
||||
errorInfo = "Reason: " + dioError.type.toString();
|
||||
errorInfo = "Reason: $dioError.type";
|
||||
}
|
||||
} else {
|
||||
if (kDebugMode) {
|
||||
|
||||
@@ -24,7 +24,7 @@ class LockScreenSettings {
|
||||
static const keyHasMigratedLockScreenChanges =
|
||||
"ls_has_migrated_lock_screen_changes";
|
||||
final List<Duration> autoLockDurations = const [
|
||||
Duration(seconds: 0),
|
||||
Duration(milliseconds: 650),
|
||||
Duration(seconds: 5),
|
||||
Duration(seconds: 15),
|
||||
Duration(minutes: 1),
|
||||
|
||||
@@ -5,6 +5,8 @@ import 'package:ente_auth/ui/components/buttons/button_widget.dart';
|
||||
import 'package:ente_auth/ui/components/dialog_widget.dart';
|
||||
import 'package:ente_auth/ui/components/models/button_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
Future<void> shareDialog(
|
||||
BuildContext context,
|
||||
@@ -49,3 +51,52 @@ Future<void> shareDialog(
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Rect _sharePosOrigin(BuildContext? context, GlobalKey? key) {
|
||||
late final Rect rect;
|
||||
if (context != null) {
|
||||
rect = shareButtonRect(context, key);
|
||||
} else {
|
||||
rect = const Offset(20.0, 20.0) & const Size(10, 10);
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
|
||||
/// Returns the rect of button if context and key are not null
|
||||
/// If key is null, returned rect will be at the center of the screen
|
||||
Rect shareButtonRect(BuildContext context, GlobalKey? shareButtonKey) {
|
||||
Size size = MediaQuery.sizeOf(context);
|
||||
final RenderObject? renderObject =
|
||||
shareButtonKey?.currentContext?.findRenderObject();
|
||||
RenderBox? renderBox;
|
||||
if (renderObject != null && renderObject is RenderBox) {
|
||||
renderBox = renderObject;
|
||||
}
|
||||
if (renderBox == null) {
|
||||
return Rect.fromLTWH(0, 0, size.width, size.height / 2);
|
||||
}
|
||||
size = renderBox.size;
|
||||
final Offset position = renderBox.localToGlobal(Offset.zero);
|
||||
return Rect.fromCenter(
|
||||
center: position + Offset(size.width / 2, size.height / 2),
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
);
|
||||
}
|
||||
|
||||
Future<ShareResult> shareText(
|
||||
String text, {
|
||||
BuildContext? context,
|
||||
GlobalKey? key,
|
||||
}) async {
|
||||
try {
|
||||
final sharePosOrigin = _sharePosOrigin(context, key);
|
||||
return Share.share(
|
||||
text,
|
||||
sharePositionOrigin: sharePosOrigin,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logger("ShareUtil").severe("failed to share text", e, s);
|
||||
return ShareResult.unavailable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,38 @@ String getNextTotp(Code code) {
|
||||
);
|
||||
}
|
||||
|
||||
// generateFutureTotpCodes generates future TOTP codes based on the current time.
|
||||
// It returns the start time and a list of future codes.
|
||||
(int, List<String>) generateFutureTotpCodes(Code code, int count) {
|
||||
final int startTime =
|
||||
((DateTime.now().millisecondsSinceEpoch ~/ 1000) ~/ code.period) *
|
||||
code.period *
|
||||
1000;
|
||||
final String secret = getSanitizedSecret(code.secret);
|
||||
final List<String> codes = [];
|
||||
if (code.type == Type.steam || code.issuer.toLowerCase() == 'steam') {
|
||||
final SteamTOTP steamTotp = SteamTOTP(secret: code.secret);
|
||||
for (int i = 0; i < count; i++) {
|
||||
int generatedTime = startTime + code.period * 1000 * i;
|
||||
codes.add(steamTotp.generate(generatedTime ~/ 1000));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < count; i++) {
|
||||
int generatedTime = startTime + code.period * 1000 * i;
|
||||
final genCode = otp.OTP.generateTOTPCodeString(
|
||||
secret,
|
||||
generatedTime,
|
||||
length: code.digits,
|
||||
interval: code.period,
|
||||
algorithm: _getAlgorithm(code),
|
||||
isGoogle: true,
|
||||
);
|
||||
codes.add(genCode);
|
||||
}
|
||||
}
|
||||
return (startTime, codes);
|
||||
}
|
||||
|
||||
otp.Algorithm _getAlgorithm(Code code) {
|
||||
switch (code.algorithm) {
|
||||
case Algorithm.sha256:
|
||||
|
||||
@@ -36,7 +36,7 @@ class WindowsProtocolHandler {
|
||||
hKey,
|
||||
txtKey,
|
||||
txtValue,
|
||||
REG_SZ,
|
||||
REG_VALUE_TYPE.REG_SZ,
|
||||
txtData,
|
||||
txtData.length * 2 + 2,
|
||||
);
|
||||
|
||||
@@ -2,8 +2,8 @@ PODS:
|
||||
- app_links (1.0.0):
|
||||
- FlutterMacOS
|
||||
- connectivity_plus (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- ReachabilitySwift
|
||||
- desktop_webview_window (0.0.1):
|
||||
- FlutterMacOS
|
||||
- device_info_plus (0.0.1):
|
||||
@@ -29,14 +29,13 @@ PODS:
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- ReachabilitySwift (5.2.3)
|
||||
- screen_retriever (0.0.1):
|
||||
- FlutterMacOS
|
||||
- Sentry/HybridSDK (8.25.0)
|
||||
- sentry_flutter (7.20.2):
|
||||
- Sentry/HybridSDK (8.33.0)
|
||||
- sentry_flutter (8.7.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- Sentry/HybridSDK (= 8.25.0)
|
||||
- Sentry/HybridSDK (= 8.33.0)
|
||||
- share_plus (0.0.1):
|
||||
- FlutterMacOS
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
@@ -47,16 +46,16 @@ PODS:
|
||||
- sqflite (0.0.3):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- "sqlite3 (3.46.0+1)":
|
||||
- "sqlite3/common (= 3.46.0+1)"
|
||||
- "sqlite3/common (3.46.0+1)"
|
||||
- "sqlite3/dbstatvtab (3.46.0+1)":
|
||||
- "sqlite3 (3.46.1+1)":
|
||||
- "sqlite3/common (= 3.46.1+1)"
|
||||
- "sqlite3/common (3.46.1+1)"
|
||||
- "sqlite3/dbstatvtab (3.46.1+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/fts5 (3.46.0+1)":
|
||||
- "sqlite3/fts5 (3.46.1+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/perf-threadsafe (3.46.0+1)":
|
||||
- "sqlite3/perf-threadsafe (3.46.1+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/rtree (3.46.0+1)":
|
||||
- "sqlite3/rtree (3.46.1+1)":
|
||||
- sqlite3/common
|
||||
- sqlite3_flutter_libs (0.0.1):
|
||||
- FlutterMacOS
|
||||
@@ -74,7 +73,7 @@ PODS:
|
||||
|
||||
DEPENDENCIES:
|
||||
- app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`)
|
||||
- connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`)
|
||||
- connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/darwin`)
|
||||
- desktop_webview_window (from `Flutter/ephemeral/.symlinks/plugins/desktop_webview_window/macos`)
|
||||
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
|
||||
- file_saver (from `Flutter/ephemeral/.symlinks/plugins/file_saver/macos`)
|
||||
@@ -100,7 +99,6 @@ DEPENDENCIES:
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- OrderedSet
|
||||
- ReachabilitySwift
|
||||
- Sentry
|
||||
- sqlite3
|
||||
|
||||
@@ -108,7 +106,7 @@ EXTERNAL SOURCES:
|
||||
app_links:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/app_links/macos
|
||||
connectivity_plus:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/darwin
|
||||
desktop_webview_window:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/desktop_webview_window/macos
|
||||
device_info_plus:
|
||||
@@ -154,7 +152,7 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a
|
||||
connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747
|
||||
connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db
|
||||
desktop_webview_window: d4365e71bcd4e1aa0c14cf0377aa24db0c16a7e2
|
||||
device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f
|
||||
file_saver: 44e6fbf666677faf097302460e214e977fdd977b
|
||||
@@ -165,17 +163,16 @@ SPEC CHECKSUMS:
|
||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||
local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3
|
||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||
package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce
|
||||
package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
ReachabilitySwift: 7f151ff156cea1481a8411701195ac6a984f4979
|
||||
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
|
||||
Sentry: cd86fc55628f5b7c572cabe66cc8f95a9d2f165a
|
||||
sentry_flutter: 0cf2507eb90ff7a6aa3304e900dd7f08edbbefdf
|
||||
share_plus: 76dd39142738f7a68dd57b05093b5e8193f220f7
|
||||
Sentry: 8560050221424aef0bebc8e31eedf00af80f90a6
|
||||
sentry_flutter: e26b861f744e5037a3faf9bf56603ec65d658a61
|
||||
share_plus: 36537c04ce0c3e3f5bd297ce4318b6d5ee5fd6cf
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sodium_libs: d39bd76697736cb11ce4a0be73b9b4bc64466d6f
|
||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||
sqlite3: 292c3e1bfe89f64e51ea7fc7dab9182a017c8630
|
||||
sqlite3: 0bb0e6389d824e40296f531b858a2a0b71c0d2fb
|
||||
sqlite3_flutter_libs: 5ca46c1a04eddfbeeb5b16566164aa7ad1616e7b
|
||||
tray_manager: 9064e219c56d75c476e46b9a21182087930baf90
|
||||
url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399
|
||||
|
||||
@@ -362,6 +362,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
dropdown_button2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dropdown_button2
|
||||
sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.9"
|
||||
email_validator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -679,14 +687,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2"
|
||||
flutter_slidable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_slidable
|
||||
sha256: "673403d2eeef1f9e8483bd6d8d92aae73b1d8bd71f382bc3930f699c731bc27c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
flutter_speed_dial:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: ente_auth
|
||||
description: ente two-factor authenticator
|
||||
version: 3.1.3+323
|
||||
version: 3.1.8+328
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
@@ -27,6 +27,7 @@ dependencies:
|
||||
device_info_plus: ^9.1.1
|
||||
dio: ^5.4.0
|
||||
dotted_border: ^2.0.0+2
|
||||
dropdown_button2: ^2.3.9
|
||||
email_validator: ^3.0.0
|
||||
ente_crypto_dart:
|
||||
git:
|
||||
@@ -58,7 +59,6 @@ dependencies:
|
||||
sdk: flutter
|
||||
flutter_native_splash: ^2.2.13
|
||||
flutter_secure_storage: ^9.0.0
|
||||
flutter_slidable: ^3.0.1
|
||||
flutter_speed_dial: ^7.0.0
|
||||
flutter_staggered_grid_view: ^0.7.0
|
||||
flutter_svg: ^2.0.5
|
||||
|
||||
@@ -89,22 +89,14 @@ If you fancy Docker, you can also run the CLI within a container.
|
||||
Modify the `docker-compose.yml` and add volume. ``cli-data`` volume is
|
||||
mandatory, you can add more volumes for your export directory.
|
||||
|
||||
Build the docker image
|
||||
|
||||
Build and run the container in detached mode
|
||||
```shell
|
||||
docker build -t ente:latest .
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
Note that [BuildKit](https://docs.docker.com/go/buildkit/) is needed to build
|
||||
this image. If you face this issue, a quick fix is to add `DOCKER_BUILDKIT=1` in
|
||||
front of the build command.
|
||||
|
||||
Start the container in detached mode
|
||||
|
||||
```shell
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
`exec` into the container
|
||||
```shell
|
||||
docker-compose exec ente-cli /bin/sh -c "./ente-cli version"
|
||||
|
||||