Add interface to manage accounts
This commit is contained in:
248
Cargo.lock
generated
248
Cargo.lock
generated
@ -17,6 +17,18 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aes"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.8.6"
|
version = "0.8.6"
|
||||||
@ -415,6 +427,15 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-padding"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blocking"
|
name = "blocking"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
@ -519,6 +540,15 @@ dependencies = [
|
|||||||
"capnp 0.17.2",
|
"capnp 0.17.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cbc"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.83"
|
version = "1.0.83"
|
||||||
@ -558,6 +588,17 @@ dependencies = [
|
|||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"inout",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.4.7"
|
version = "4.4.7"
|
||||||
@ -663,6 +704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
|
"rand_core",
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -685,6 +727,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer",
|
"block-buffer",
|
||||||
"crypto-common",
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1343,6 +1386,24 @@ version = "0.4.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hkdf"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
|
||||||
|
dependencies = [
|
||||||
|
"hmac",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
@ -1481,6 +1542,16 @@ dependencies = [
|
|||||||
"hashbrown 0.14.2",
|
"hashbrown 0.14.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inout"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||||
|
dependencies = [
|
||||||
|
"block-padding",
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
@ -1536,6 +1607,9 @@ name = "lazy_static"
|
|||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
dependencies = [
|
||||||
|
"spin 0.5.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libadwaita"
|
name = "libadwaita"
|
||||||
@ -1575,6 +1649,12 @@ version = "0.2.150"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libm"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsqlite3-sys"
|
name = "libsqlite3-sys"
|
||||||
version = "0.26.0"
|
version = "0.26.0"
|
||||||
@ -1755,6 +1835,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"futures",
|
"futures",
|
||||||
"generational-arena",
|
"generational-arena",
|
||||||
|
"oo7",
|
||||||
"rand",
|
"rand",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@ -1779,6 +1860,91 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint-dig"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"lazy_static",
|
||||||
|
"libm",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-traits",
|
||||||
|
"rand",
|
||||||
|
"serde",
|
||||||
|
"smallvec",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
@ -1832,6 +1998,33 @@ version = "1.18.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oo7"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "220729ba847d98e1a9902c05e41dae79ce4a0b913dad68bc540dd3120a8c2b6b"
|
||||||
|
dependencies = [
|
||||||
|
"aes",
|
||||||
|
"async-global-executor",
|
||||||
|
"async-std",
|
||||||
|
"byteorder",
|
||||||
|
"cbc",
|
||||||
|
"cipher",
|
||||||
|
"digest",
|
||||||
|
"futures-util",
|
||||||
|
"hkdf",
|
||||||
|
"hmac",
|
||||||
|
"num",
|
||||||
|
"num-bigint-dig",
|
||||||
|
"once_cell",
|
||||||
|
"pbkdf2",
|
||||||
|
"rand",
|
||||||
|
"serde",
|
||||||
|
"sha2",
|
||||||
|
"zbus",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
version = "0.10.59"
|
version = "0.10.59"
|
||||||
@ -1946,6 +2139,16 @@ dependencies = [
|
|||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pbkdf2"
|
||||||
|
version = "0.12.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
"hmac",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
@ -2211,7 +2414,7 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"libc",
|
"libc",
|
||||||
"spin",
|
"spin 0.9.8",
|
||||||
"untrusted",
|
"untrusted",
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
@ -2437,6 +2640,17 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@ -2525,6 +2739,12 @@ dependencies = [
|
|||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.9.8"
|
version = "0.9.8"
|
||||||
@ -2543,6 +2763,12 @@ version = "0.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.109"
|
version = "1.0.109"
|
||||||
@ -3303,6 +3529,26 @@ dependencies = [
|
|||||||
"syn 2.0.39",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
|
||||||
|
dependencies = [
|
||||||
|
"zeroize_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize_derive"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.39",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zvariant"
|
name = "zvariant"
|
||||||
version = "3.15.0"
|
version = "3.15.0"
|
||||||
|
|||||||
@ -5,6 +5,7 @@ blueprints = custom_target('blueprints',
|
|||||||
'ui/window.blp',
|
'ui/window.blp',
|
||||||
'ui/shortcuts.blp',
|
'ui/shortcuts.blp',
|
||||||
'ui/subscription_info_dialog.blp',
|
'ui/subscription_info_dialog.blp',
|
||||||
|
'ui/preferences.blp',
|
||||||
),
|
),
|
||||||
output: '.',
|
output: '.',
|
||||||
command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'],
|
command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'],
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
<file compressed="true" preprocess="xml-stripblanks" alias="gtk/help-overlay.ui">ui/shortcuts.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks" alias="gtk/help-overlay.ui">ui/shortcuts.ui</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">ui/window.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks">ui/window.ui</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">ui/subscription_info_dialog.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks">ui/subscription_info_dialog.ui</file>
|
||||||
|
<file compressed="true" preprocess="xml-stripblanks">ui/preferences.ui</file>
|
||||||
<file compressed="true">style.css</file>
|
<file compressed="true">style.css</file>
|
||||||
<file compressed="true">com.ranfdev.Notify.metainfo.xml</file>
|
<file compressed="true">com.ranfdev.Notify.metainfo.xml</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
|
|||||||
35
data/resources/ui/preferences.blp
Normal file
35
data/resources/ui/preferences.blp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using Gtk 4.0;
|
||||||
|
using Adw 1;
|
||||||
|
|
||||||
|
template $NotifyPreferences : Adw.PreferencesWindow {
|
||||||
|
width-request: 240;
|
||||||
|
height-request: 360;
|
||||||
|
Adw.PreferencesPage {
|
||||||
|
title: "Accounts";
|
||||||
|
description: "Accounts to access protected topics";
|
||||||
|
Adw.PreferencesGroup {
|
||||||
|
title: "New Account";
|
||||||
|
Adw.EntryRow server_entry {
|
||||||
|
title: "server";
|
||||||
|
}
|
||||||
|
Adw.EntryRow username_entry {
|
||||||
|
title: "username";
|
||||||
|
}
|
||||||
|
Adw.PasswordEntryRow password_entry {
|
||||||
|
title: "password";
|
||||||
|
}
|
||||||
|
Gtk.Button add_btn {
|
||||||
|
margin-top: 8;
|
||||||
|
styles ["suggested-action"]
|
||||||
|
halign: end;
|
||||||
|
label: "Add";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Adw.PreferencesGroup added_accounts_group {
|
||||||
|
title: "Added";
|
||||||
|
Gtk.ListBox added_accounts {
|
||||||
|
styles ["boxed-list"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -28,3 +28,4 @@ generational-arena = "0.2.9"
|
|||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
thiserror = "1.0.49"
|
thiserror = "1.0.49"
|
||||||
regex = "1.9.6"
|
regex = "1.9.6"
|
||||||
|
oo7 = "0.2.1"
|
||||||
|
|||||||
@ -7,6 +7,7 @@ pub mod ntfy_capnp {
|
|||||||
include!(concat!(env!("OUT_DIR"), "/src/ntfy_capnp.rs"));
|
include!(concat!(env!("OUT_DIR"), "/src/ntfy_capnp.rs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -15,6 +16,7 @@ pub struct SharedEnv {
|
|||||||
proxy: Arc<dyn models::NotificationProxy>,
|
proxy: Arc<dyn models::NotificationProxy>,
|
||||||
http: reqwest::Client,
|
http: reqwest::Client,
|
||||||
network: Arc<dyn models::NetworkMonitorProxy>,
|
network: Arc<dyn models::NetworkMonitorProxy>,
|
||||||
|
keyring: Rc<oo7::Keyring>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
|||||||
@ -33,9 +33,16 @@ interface Subscription {
|
|||||||
clearNotifications @5 ();
|
clearNotifications @5 ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Account {
|
||||||
|
server @0 :Text;
|
||||||
|
username @1 :Text;
|
||||||
|
}
|
||||||
|
|
||||||
interface SystemNotifier {
|
interface SystemNotifier {
|
||||||
subscribe @0 (server: Text, topic: Text) -> (subscription: Subscription);
|
subscribe @0 (server: Text, topic: Text) -> (subscription: Subscription);
|
||||||
unsubscribe @1 (server: Text, topic: Text);
|
unsubscribe @1 (server: Text, topic: Text);
|
||||||
listSubscriptions @2 () -> (list: List(Subscription));
|
listSubscriptions @2 () -> (list: List(Subscription));
|
||||||
|
addAccount @3 (account: Account, password: Text);
|
||||||
|
removeAccount @4 (account: Account);
|
||||||
|
listAccounts @5 () -> (list: List(Account));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, OnceCell, RefCell};
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -20,7 +20,7 @@ use crate::SharedEnv;
|
|||||||
use crate::{
|
use crate::{
|
||||||
message_repo::Db,
|
message_repo::Db,
|
||||||
models::{self, MinMessage},
|
models::{self, MinMessage},
|
||||||
ntfy_capnp::{output_channel, subscription, system_notifier, watch_handle, Status},
|
ntfy_capnp::{account, output_channel, subscription, system_notifier, watch_handle, Status},
|
||||||
topic_listener::{build_client, TopicListener},
|
topic_listener::{build_client, TopicListener},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -343,6 +343,7 @@ impl SystemNotifier {
|
|||||||
dbpath: &str,
|
dbpath: &str,
|
||||||
notification_proxy: Arc<dyn models::NotificationProxy>,
|
notification_proxy: Arc<dyn models::NotificationProxy>,
|
||||||
network: Arc<dyn models::NetworkMonitorProxy>,
|
network: Arc<dyn models::NetworkMonitorProxy>,
|
||||||
|
keyring: oo7::Keyring,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
watching: Rc::new(RefCell::new(HashMap::new())),
|
watching: Rc::new(RefCell::new(HashMap::new())),
|
||||||
@ -351,6 +352,7 @@ impl SystemNotifier {
|
|||||||
proxy: notification_proxy,
|
proxy: notification_proxy,
|
||||||
http: build_client().unwrap(),
|
http: build_client().unwrap(),
|
||||||
network,
|
network,
|
||||||
|
keyring: Rc::new(keyring),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -450,6 +452,86 @@ impl system_notifier::Server for SystemNotifier {
|
|||||||
|
|
||||||
Promise::ok(())
|
Promise::ok(())
|
||||||
}
|
}
|
||||||
|
fn list_accounts(
|
||||||
|
&mut self,
|
||||||
|
_: system_notifier::ListAccountsParams,
|
||||||
|
mut results: system_notifier::ListAccountsResults,
|
||||||
|
) -> capnp::capability::Promise<(), capnp::Error> {
|
||||||
|
let keyring = self.env.keyring.clone();
|
||||||
|
|
||||||
|
Promise::from_future(async move {
|
||||||
|
let attrs = HashMap::from([("type", "password")]);
|
||||||
|
let values = keyring
|
||||||
|
.search_items(attrs)
|
||||||
|
.await
|
||||||
|
.map_err(|e| capnp::Error::failed(e.to_string()))?;
|
||||||
|
|
||||||
|
let mut list = results.get().init_list(values.len() as u32);
|
||||||
|
for (i, item) in values.iter().enumerate() {
|
||||||
|
let attrs = item
|
||||||
|
.attributes()
|
||||||
|
.await
|
||||||
|
.map_err(|e| capnp::Error::failed(e.to_string()))?;
|
||||||
|
let mut acc = list.reborrow().get(i as u32);
|
||||||
|
acc.set_username(attrs["username"][..].into());
|
||||||
|
acc.set_server(attrs["server"][..].into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn add_account(
|
||||||
|
&mut self,
|
||||||
|
params: system_notifier::AddAccountParams,
|
||||||
|
mut results: system_notifier::AddAccountResults,
|
||||||
|
) -> capnp::capability::Promise<(), capnp::Error> {
|
||||||
|
let keyring = self.env.keyring.clone();
|
||||||
|
Promise::from_future(async move {
|
||||||
|
let account = params.get()?.get_account()?;
|
||||||
|
let username = account.get_username()?.to_str()?;
|
||||||
|
let server = account.get_server()?.to_str()?;
|
||||||
|
let password = params.get()?.get_password()?.to_str()?;
|
||||||
|
|
||||||
|
let attrs = HashMap::from([
|
||||||
|
("type", "password"),
|
||||||
|
("username", username),
|
||||||
|
("server", server),
|
||||||
|
]);
|
||||||
|
keyring
|
||||||
|
.create_item("Password", attrs, password, true)
|
||||||
|
.await
|
||||||
|
.map_err(|e| capnp::Error::failed(e.to_string()))?;
|
||||||
|
|
||||||
|
info!(server = %server, username = %username, "added account");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn remove_account(
|
||||||
|
&mut self,
|
||||||
|
params: system_notifier::RemoveAccountParams,
|
||||||
|
mut results: system_notifier::RemoveAccountResults,
|
||||||
|
) -> capnp::capability::Promise<(), capnp::Error> {
|
||||||
|
let keyring = self.env.keyring.clone();
|
||||||
|
Promise::from_future(async move {
|
||||||
|
let account = params.get()?.get_account()?;
|
||||||
|
let username = account.get_username()?.to_str()?;
|
||||||
|
let server = account.get_server()?.to_str()?;
|
||||||
|
|
||||||
|
let attrs = HashMap::from([
|
||||||
|
("type", "password"),
|
||||||
|
("username", username),
|
||||||
|
("server", server),
|
||||||
|
]);
|
||||||
|
keyring
|
||||||
|
.delete(attrs)
|
||||||
|
.await
|
||||||
|
.map_err(|e| capnp::Error::failed(e.to_string()))?;
|
||||||
|
|
||||||
|
info!(server = %server, username = %username, "removed account");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(
|
pub fn start(
|
||||||
@ -467,10 +549,17 @@ pub fn start(
|
|||||||
UnixListener::bind(&socket_path).unwrap()
|
UnixListener::bind(&socket_path).unwrap()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let keyring = rt.block_on(async {
|
||||||
|
oo7::Keyring::new()
|
||||||
|
.await
|
||||||
|
.expect("Failed to start Secret Service")
|
||||||
|
});
|
||||||
|
|
||||||
let dbpath = dbpath.to_owned();
|
let dbpath = dbpath.to_owned();
|
||||||
let f = move || {
|
let f = move || {
|
||||||
let local = tokio::task::LocalSet::new();
|
let local = tokio::task::LocalSet::new();
|
||||||
let mut system_notifier = SystemNotifier::new(&dbpath, notification_proxy, network_proxy);
|
let mut system_notifier =
|
||||||
|
SystemNotifier::new(&dbpath, notification_proxy, network_proxy, keyring);
|
||||||
local.spawn_local(async move {
|
local.spawn_local(async move {
|
||||||
system_notifier.watch_subscribed().await.unwrap();
|
system_notifier.watch_subscribed().await.unwrap();
|
||||||
let system_client: system_notifier::Client = capnp_rpc::new_client(system_notifier);
|
let system_client: system_notifier::Client = capnp_rpc::new_client(system_notifier);
|
||||||
|
|||||||
@ -133,6 +133,12 @@ impl NotifyApplication {
|
|||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
let action_about = gio::ActionEntry::builder("preferences")
|
||||||
|
.activate(|app: &Self, _, _| {
|
||||||
|
app.show_preferences();
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
|
||||||
let message_action = gio::ActionEntry::builder("message-action")
|
let message_action = gio::ActionEntry::builder("message-action")
|
||||||
.parameter_type(Some(&glib::VariantTy::STRING))
|
.parameter_type(Some(&glib::VariantTy::STRING))
|
||||||
.activate(|app: &Self, _, params| {
|
.activate(|app: &Self, _, params| {
|
||||||
@ -214,6 +220,14 @@ impl NotifyApplication {
|
|||||||
dialog.present();
|
dialog.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn show_preferences(&self) {
|
||||||
|
let win = crate::widgets::NotifyPreferences::new(
|
||||||
|
self.main_window().imp().notifier.get().unwrap().clone(),
|
||||||
|
);
|
||||||
|
win.set_transient_for(Some(&self.main_window()));
|
||||||
|
win.present();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(&self) -> glib::ExitCode {
|
pub fn run(&self) -> glib::ExitCode {
|
||||||
info!(app_id = %APP_ID, version = %VERSION, profile = %PROFILE, datadir = %PKGDATADIR, "running");
|
info!(app_id = %APP_ID, version = %VERSION, profile = %PROFILE, datadir = %PKGDATADIR, "running");
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
mod add_subscription_dialog;
|
mod add_subscription_dialog;
|
||||||
mod advanced_message_dialog;
|
mod advanced_message_dialog;
|
||||||
mod message_row;
|
mod message_row;
|
||||||
|
mod preferences;
|
||||||
mod subscription_info_dialog;
|
mod subscription_info_dialog;
|
||||||
mod window;
|
mod window;
|
||||||
pub use add_subscription_dialog::AddSubscriptionDialog;
|
pub use add_subscription_dialog::AddSubscriptionDialog;
|
||||||
pub use advanced_message_dialog::*;
|
pub use advanced_message_dialog::*;
|
||||||
pub use message_row::*;
|
pub use message_row::*;
|
||||||
|
pub use preferences::*;
|
||||||
pub use subscription_info_dialog::SubscriptionInfoDialog;
|
pub use subscription_info_dialog::SubscriptionInfoDialog;
|
||||||
pub use window::*;
|
pub use window::*;
|
||||||
|
|||||||
179
src/widgets/preferences.rs
Normal file
179
src/widgets/preferences.rs
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
use std::cell::Cell;
|
||||||
|
use std::cell::OnceCell;
|
||||||
|
|
||||||
|
use adw::prelude::*;
|
||||||
|
use adw::subclass::prelude::*;
|
||||||
|
use futures::prelude::*;
|
||||||
|
use gtk::{gio, glib};
|
||||||
|
use ntfy_daemon::models;
|
||||||
|
use ntfy_daemon::ntfy_capnp::{system_notifier, Status};
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
|
use crate::application::NotifyApplication;
|
||||||
|
use crate::config::{APP_ID, PROFILE};
|
||||||
|
use crate::subscription::Subscription;
|
||||||
|
use crate::widgets::*;
|
||||||
|
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(gtk::CompositeTemplate)]
|
||||||
|
#[template(resource = "/com/ranfdev/Notify/ui/preferences.ui")]
|
||||||
|
pub struct NotifyPreferences {
|
||||||
|
#[template_child]
|
||||||
|
pub server_entry: TemplateChild<adw::EntryRow>,
|
||||||
|
#[template_child]
|
||||||
|
pub username_entry: TemplateChild<adw::EntryRow>,
|
||||||
|
#[template_child]
|
||||||
|
pub password_entry: TemplateChild<adw::PasswordEntryRow>,
|
||||||
|
#[template_child]
|
||||||
|
pub add_btn: TemplateChild<gtk::Button>,
|
||||||
|
#[template_child]
|
||||||
|
pub added_accounts: TemplateChild<gtk::ListBox>,
|
||||||
|
#[template_child]
|
||||||
|
pub added_accounts_group: TemplateChild<adw::PreferencesGroup>,
|
||||||
|
pub notifier: OnceCell<system_notifier::Client>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for NotifyPreferences {
|
||||||
|
fn default() -> Self {
|
||||||
|
let this = Self {
|
||||||
|
server_entry: Default::default(),
|
||||||
|
username_entry: Default::default(),
|
||||||
|
password_entry: Default::default(),
|
||||||
|
add_btn: Default::default(),
|
||||||
|
added_accounts: Default::default(),
|
||||||
|
added_accounts_group: Default::default(),
|
||||||
|
notifier: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for NotifyPreferences {
|
||||||
|
const NAME: &'static str = "NotifyPreferences";
|
||||||
|
type Type = super::NotifyPreferences;
|
||||||
|
type ParentType = adw::PreferencesWindow;
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.bind_template();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||||
|
obj.init_template();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for NotifyPreferences {
|
||||||
|
fn dispose(&self) {
|
||||||
|
self.dispose_template();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetImpl for NotifyPreferences {}
|
||||||
|
impl WindowImpl for NotifyPreferences {}
|
||||||
|
|
||||||
|
impl ApplicationWindowImpl for NotifyPreferences {}
|
||||||
|
impl AdwWindowImpl for NotifyPreferences {}
|
||||||
|
impl PreferencesWindowImpl for NotifyPreferences {}
|
||||||
|
}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct NotifyPreferences(ObjectSubclass<imp::NotifyPreferences>)
|
||||||
|
@extends gtk::Widget, gtk::Window, adw::Window, adw::PreferencesWindow,
|
||||||
|
@implements gio::ActionMap, gio::ActionGroup, gtk::Root;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NotifyPreferences {
|
||||||
|
pub fn new(notifier: system_notifier::Client) -> Self {
|
||||||
|
let obj: Self = glib::Object::builder().build();
|
||||||
|
obj.imp()
|
||||||
|
.notifier
|
||||||
|
.set(notifier)
|
||||||
|
.map_err(|_| "notifier")
|
||||||
|
.unwrap();
|
||||||
|
let this = obj.clone();
|
||||||
|
obj.imp().add_btn.connect_clicked(move |btn| {
|
||||||
|
let this = this.clone();
|
||||||
|
btn.spawn_with_near_toast(async move { this.add_account().await });
|
||||||
|
});
|
||||||
|
let this = obj.clone();
|
||||||
|
obj.imp()
|
||||||
|
.added_accounts
|
||||||
|
.spawn_with_near_toast(async move { this.show_accounts().await });
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn show_accounts(&self) -> anyhow::Result<()> {
|
||||||
|
let imp = self.imp();
|
||||||
|
let req = imp.notifier.get().unwrap().list_accounts_request();
|
||||||
|
let res = req.send().promise.await?;
|
||||||
|
|
||||||
|
let accounts = res.get()?.get_list()?;
|
||||||
|
|
||||||
|
imp.added_accounts_group.set_visible(!accounts.is_empty());
|
||||||
|
|
||||||
|
imp.added_accounts.remove_all();
|
||||||
|
for a in accounts {
|
||||||
|
let server = a.get_server()?.to_string()?;
|
||||||
|
let username = a.get_username()?.to_string()?;
|
||||||
|
|
||||||
|
let row = adw::ActionRow::builder()
|
||||||
|
.title(&server)
|
||||||
|
.subtitle(&username)
|
||||||
|
.build();
|
||||||
|
row.add_css_class("property");
|
||||||
|
row.add_suffix(&{
|
||||||
|
let btn = gtk::Button::builder()
|
||||||
|
.icon_name("user-trash-symbolic")
|
||||||
|
.build();
|
||||||
|
btn.add_css_class("flat");
|
||||||
|
let this = self.clone();
|
||||||
|
btn.connect_clicked(move |btn| {
|
||||||
|
let this = this.clone();
|
||||||
|
let username = username.clone();
|
||||||
|
let server = server.clone();
|
||||||
|
btn.spawn_with_near_toast(async move {
|
||||||
|
this.remove_account(&server, &username).await
|
||||||
|
});
|
||||||
|
});
|
||||||
|
btn
|
||||||
|
});
|
||||||
|
imp.added_accounts.append(&row);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub async fn add_account(&self) -> anyhow::Result<()> {
|
||||||
|
let imp = self.imp();
|
||||||
|
let password = imp.password_entry.text();
|
||||||
|
let server = imp.server_entry.text();
|
||||||
|
let username = imp.username_entry.text();
|
||||||
|
|
||||||
|
let mut req = imp.notifier.get().unwrap().add_account_request();
|
||||||
|
let mut acc = req.get().get_account()?;
|
||||||
|
acc.set_username(username[..].into());
|
||||||
|
acc.set_server(server[..].into());
|
||||||
|
req.get().set_password(password[..].into());
|
||||||
|
|
||||||
|
let res = req.send().promise.await?;
|
||||||
|
|
||||||
|
self.show_accounts().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub async fn remove_account(&self, server: &str, username: &str) -> anyhow::Result<()> {
|
||||||
|
let mut req = self.imp().notifier.get().unwrap().remove_account_request();
|
||||||
|
let mut acc = req.get().get_account()?;
|
||||||
|
|
||||||
|
acc.set_username(username[..].into());
|
||||||
|
acc.set_server(server[..].into());
|
||||||
|
|
||||||
|
req.send().promise.await?;
|
||||||
|
|
||||||
|
self.show_accounts().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user